Currently, I have a DropDown
implemented with particular types. I would like to make that drop-down menu generic so I can reuse it everywhere with custom objects and remove boilerplate code.
Current Implementation
@Composable
fun SingleLineDropDown(optionsFieldState: OptionsFieldState<String>, hintText: String, isEditable: Boolean = true) {
var expanded by remember { mutableStateOf(false) }
var textFieldSize by remember { mutableStateOf(Size.Zero) }
val icon = if (expanded) Icons.Filled.KeyboardArrowUp else Icons.Filled.KeyboardArrowDown
val modifier = if (isEditable) {
Modifier.clickable { expanded = !expanded }
} else Modifier
Box {
EditableRow(
value = optionsFieldState.value ?: "",
onValueChange = { optionsFieldState.value = it },
enabled = false,
error = optionsFieldState.error.orEmpty(),
modifier = modifier
.fillMaxWidth()
.onGloballyPositioned { coordinates ->
//This value is used to assign to the DropDown the same width
textFieldSize = coordinates.size.toSize()
},
hintText = hintText,
trailingIcon = {
Icon(
icon, null, modifier
)
},
colors = TextFieldDefaults.outlinedTextFieldColors(
disabledTextColor = if (isEditable) MaterialTheme.colors.onBackground else Color.LightGray
)
)
if (isEditable) {
DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
modifier = Modifier.width(with(LocalDensity.current) { textFieldSize.width.toDp() })
) {
optionsFieldState.options.forEach { option ->
DropdownMenuItem(onClick = {
optionsFieldState.value = option
expanded = !expanded
}) {
Text(text = option)
}
}
}
}
}
}
Caller function
SingleLineDropDown(
optionsFieldState = state.province,
hintText = stringResource(id = R.string.province_territory),
isEditable = state.isAddressEditable
)
OptionFiledState is custom state for compose UI
open class OptionsFieldState<T>(
initialValue: T?,
options: List<T> = listOf(),
validators: List<Validator> = listOf(),
onValueChanged: () -> Unit = {},
)