OutlinedTextField doesn't produce PressInteraction.Press interactions on desktop and ios
I am building an expense app in compose multiplatform (1.5.0) but I have an issue with this
@Composable
fun ExposedDropdownMenu(
state: MutableState<String>,
items: List<String>,
selected: String = items[0],
onItemSelected: (String) -> Unit,
colors: TextFieldColors = TextFieldDefaults.textFieldColors(
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent
),
textStyle: TextStyle = MaterialTheme.typography.body1.copy(
fontWeight = FontWeight.Normal,
fontSize = 14.sp
),
) {
var expanded by remember { mutableStateOf(false) }
val interactionSource = remember { MutableInteractionSource() }
LaunchedEffect(interactionSource) {
interactionSource.interactions
.filter { it is PressInteraction.Press }
.collect {
expanded = !expanded
}
}
ExposedDropdownMenuStack(
textField = {
OutlinedTextField(
value = if (state.value == "") selected else state.value,
onValueChange = {
state.value = it
},
interactionSource = interactionSource,
readOnly = true,
colors = colors,
singleLine = true,
textStyle = textStyle,
trailingIcon = {
val rotation by animateFloatAsState(if (expanded) 180F else 0F)
Icon(
rememberVectorPainter(Icons.Default.ArrowDropDown),
contentDescription = "Dropdown Arrow",
Modifier.rotate(rotation),
)
},
modifier = Modifier.fillMaxWidth()
)
},
dropdownMenu = { boxWidth, itemHeight ->
Box(
Modifier
.width(boxWidth)
.wrapContentSize(Alignment.TopStart)
) {
DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false }
) {
items.forEach { item ->
DropdownMenuItem(
modifier = Modifier
.height(itemHeight)
.width(boxWidth),
onClick = {
expanded = false
state.value = item
onItemSelected(item)
}
) {
Text(
text = item,
style = textStyle,
modifier = Modifier.fillMaxWidth()
)
}
}
}
}
}
)
}
@Composable
private fun ExposedDropdownMenuStack(
textField: @Composable () -> Unit,
dropdownMenu: @Composable (boxWidth: Dp, itemHeight: Dp) -> Unit
) {
SubcomposeLayout { constraints ->
val textFieldPlaceable =
subcompose(ExposedDropdownMenuSlot.TextField, textField).first().measure(constraints)
val dropdownPlaceable = subcompose(ExposedDropdownMenuSlot.Dropdown) {
dropdownMenu(textFieldPlaceable.width.toDp(), textFieldPlaceable.height.toDp())
}.first().measure(constraints)
layout(textFieldPlaceable.width, textFieldPlaceable.height) {
textFieldPlaceable.placeRelative(0, 0)
dropdownPlaceable.placeRelative(0, textFieldPlaceable.height)
}
}
}
private enum class ExposedDropdownMenuSlot { TextField, Dropdown }
In Android, it's working fine but on iOS it does not work on clicking. But also I have trouble hiding the keyboard as items appear to be hidden under the keyboard in Android the manifest file I can adjust resize to that when the keyboard appears then it pushes content upwards.
@Composable
fun DropDownField(
label: String = "",
onValueChange: (String) -> Unit,
state: MutableState<String>,
items: List<String>
) {
ExposedDropdownMenu(
state = state,
items = items,
selected = label,
onItemSelected = onValueChange
)
}
Here is my list
CustomTextField.DropDownField(
state = category,
label = "Category",
items = categories.keys.toList(),
onValueChange = {
category.value = it
})
categories[category.value]?.toList()?.let {
CustomTextField.DropDownField(
state = subcategory,
label = "Sub-Category",
items = it,
onValueChange = {
subcategory.value = it
})
}
and here is the list
val category = remember { mutableStateOf("") }
val subcategory = remember { mutableStateOf("") }
var amount by remember { mutableLongStateOf(0L) }
var description by remember { mutableStateOf("") }
// Map of categories to their subcategories
val categories = mapOf(
"Transport" to listOf("Fuel", "Public Transit", "Maintenance"),
"Groceries" to listOf("Food", "Household Items"),
"Entertainment" to listOf("Movies", "Concerts", "Games"),
)
Simplified a reproducer (https://github.com/eymar/repr_ios_subcompose_layout_click):
@Composable
internal fun App() = MaterialTheme {
Column {
Spacer(modifier = Modifier.height(200.dp))
val interactionSource = remember { MutableInteractionSource() }
LaunchedEffect(interactionSource) {
interactionSource.interactions
.collect { println("Interaction = $it") }
}
OutlinedTextField(
value = "Try click me",
onValueChange = {},
interactionSource = interactionSource,
readOnly = true,
singleLine = true,
modifier = Modifier.fillMaxWidth()
)
}
}
On iOS and desktop it never prints androidx.compose.foundation.interaction.PressInteraction$Press, only androidx.compose.foundation.interaction.FocusInteraction$Focus.
But on android it prints both.
It means the issue is not with subcompose layout, but with OutlinedTextField.
You can try to change your code to not rely on PressInteraction.Press to workaround the issue for now.
Note for our team: For the reproducer in mpp:demo have a look at https://github.com/JetBrains/compose-multiplatform-core/commit/3e390ddf9893f1360f85936f553b512ab34384f3#diff-d39ddc7e61fa5922223e673e2c9a3a82682d808f3394404b7250d302b3a25327R28
Thank you Sir.
Any updates on this issue?