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 = {},
)
If you want your drop-down menu to be applicable to generics custom objects, you can change your
SingleLineDropDownfunction with generics, along side one extra parameters for the function to make it workFollow this example to understand how it can be done:
Now you can use it the following way:
Update You can also provide a default value for the generic to be used in the
EditableRow, something like that: