Damian Zawadzki
10/11/2021, 5:35 PMDamian Zawadzki
10/11/2021, 5:43 PMdata class Suggestion(val description: String)
@Stable
interface DropdownFormFieldState {
var expanded: Boolean
val suggestions: List<Suggestion>
var selected: Suggestion?
var textFieldSize: Size
}
@Composable
fun rememberDropdownFormFieldState(
expanded: Boolean = false,
suggestions: List<Suggestion>,
selected: Suggestion? = null,
textFieldSize: Size = Size.Zero,
) = DropdownFormFieldState(
expanded = expanded,
suggestions = suggestions,
selected = selected,
textFieldSize = textFieldSize,
)
fun DropdownFormFieldState(
expanded: Boolean,
suggestions: List<Suggestion>,
selected: Suggestion?,
textFieldSize: Size
): DropdownFormFieldState = DropdownFormFieldStateImpl(
expanded = expanded,
suggestions = suggestions,
selected = selected,
textFieldSize = textFieldSize,
)
internal class DropdownFormFieldStateImpl(
expanded: Boolean,
override val suggestions: List<Suggestion>,
selected: Suggestion?,
textFieldSize: Size
) : DropdownFormFieldState {
override var expanded: Boolean by mutableStateOf(expanded)
override var selected: Suggestion? by mutableStateOf(selected)
override var textFieldSize: Size by mutableStateOf(textFieldSize)
}
@Composable
fun DropdownFormField(
modifier: Modifier = Modifier,
label: String,
expanded: Boolean,
suggestions: List<Suggestion>,
selected: Suggestion? = null,
onSelected: (suggestion: Suggestion) -> Unit
) {
val state = rememberDropdownFormFieldState(
expanded = expanded,
suggestions = suggestions,
selected = selected,
)
LaunchedEffect(selected) {
if (selected != state.selected) {
state.selected?.let {
onSelected(it)
}
}
}
DropdownFormField(
modifier = modifier,
label,
state = state
)
}
@Composable
fun DropdownFormField(
modifier: Modifier = Modifier,
label: String,
state: DropdownFormFieldState,
) {
val icon = if (state.expanded)
Icons.Filled.ArrowDropUp
else
Icons.Filled.ArrowDropDown
Box(
modifier = modifier
) {
val focusRequester = remember { FocusRequester() }
val focusManager = LocalFocusManager.current
SideEffect {
if (state.expanded) {
focusRequester.requestFocus()
}
}
OutlinedTextField(
value = state.selected?.description?.takeIf { !state.expanded } ?: "",
readOnly = true,
onValueChange = { /*selectedText = it */ },
modifier = Modifier
.fillMaxWidth()
.onGloballyPositioned { coordinates ->
//This value is used to assign to the DropDown the same width
state.textFieldSize = coordinates.size.toSize()
}
.focusRequester(focusRequester)
.onFocusChanged { focusState ->
state.expanded = focusState.isFocused
},
label = { Text(label) },
trailingIcon = {
Icon(icon, "contentDescription",
Modifier.clickable {
if (state.expanded) {
focusManager.clearFocus()
} else {
focusRequester.requestFocus()
}
})
},
)
DropdownMenu(
expanded = state.expanded,
onDismissRequest = {
focusManager.clearFocus()
},
) {
state.suggestions.forEach { suggestion ->
val isCurrentSelected = suggestion == state.selected
DropdownMenuItem(
onClick = {
state.selected = suggestion
focusManager.clearFocus()
}) {
Text(text = suggestion.description)
}
}
}
}
}
Damian Zawadzki
10/11/2021, 6:22 PM