The issue I faced was that I needed AlertDialog
with some kind of List items (e. g. LazyColumn) and the TextField
to search across these items. I wanted to display all the Dialog layout even when Keyboard is opened. But what I got is a Keyboard that cover some part of Dialog layout itself. I tried to use imePadding()
for Dialog's Modifier
but seems that Dialog ignoring that. I didn't find any solution for this on the Internet.
My code looks like so:
AlertDialog(
modifier = Modifier.fillMaxWidth()
.padding(AppTheme.margins.edge)
.imePadding(),
onDismissRequest = {
searchText = TextFieldValue("")
viewModel.clearSearchQuery()
dismissCallback?.invoke()
},
text = {
Column(
modifier = Modifier.wrapContentHeight()
) {
Text(
text = stringResource(R.string.dlg_select_content_title),
style = AppTheme.textStyles.hugeTitleText
)
OutlinedTextField(
modifier = Modifier
.fillMaxWidth()
.padding(top = AppTheme.margins.divRegular),
value = searchText,
placeholderText = stringResource(R.string.dlg_select_content_search_placeholder),
onValueChange = { newValue ->
searchText = newValue
viewModel.onSearchTextTyped(newValue.text)
}
)
RadioGroup(
modifier = Modifier
.verticalScroll(rememberScrollState()),
options = labels.map {
RadioOption(
title = it.name,
description = null,
selected = vmState.selectedLabel?.id == it.id,
tag = it.id
)
},
onOptionSelected = {
searchText = TextFieldValue("")
viewModel.clearSearchQuery()
viewModel.saveLabelSelection(it.tag as Int) {
dismissCallback?.invoke()
}
}
)
}
},
properties = DialogProperties(
usePlatformDefaultWidth = false
),
confirmButton = {
// Nothing
}
)
And the result:
I am not able to interact with several last items in list because Keyboard covers it.
I have implemented a solution for this issue. The solution is quite ugly, but working. If someone knows a more elegant solution, feel free to write it in an answer in this question.
Even though the dialog ignores the imePadding()
we still can set the height. So, first of all we should to know what screen height available above keyboard.
@Composable
private fun TrickyHeight(
onHeightChanged: (Dp) -> Unit,
) {
val density = LocalDensity.current
Box(
modifier = Modifier
.fillMaxSize()
.imePadding()
.padding(bottom = 30.dp) // additional padding
.onSizeChanged {
onHeightChanged.invoke(with(density) { it.height.toDp() })
}
)
}
Next step is to create wrapper over AlertDialog
:
@Composable
fun TrickyDialog(
onDismissRequest: () -> Unit,
confirmButton: @Composable () -> Unit,
dismissButton: @Composable (() -> Unit)? = null,
icon: @Composable (() -> Unit)? = null,
title: @Composable (() -> Unit)? = null,
text: @Composable (() -> Unit)? = null,
shape: Shape = AlertDialogDefaults.shape,
containerColor: Color = AppTheme.colors.surfaceColor,
iconContentColor: Color = AlertDialogDefaults.iconContentColor,
titleContentColor: Color = AlertDialogDefaults.titleContentColor,
textContentColor: Color = AlertDialogDefaults.textContentColor,
tonalElevation: Dp = AlertDialogDefaults.TonalElevation,
properties: DialogProperties = DialogProperties()
) {
val maxDialogHeight = remember { mutableStateOf(0.dp) }
TrickyHeight(onHeightChanged = { maxDialogHeight.value = it })
AlertDialog(
modifier = Modifier
.fillMaxWidth()
.heightIn(0.dp, maxDialogHeight.value)
.padding(AppTheme.margins.edge),
onDismissRequest = onDismissRequest,
confirmButton = confirmButton,
dismissButton = dismissButton,
icon = icon,
title = title,
text = text,
shape = shape,
containerColor = containerColor,
iconContentColor = iconContentColor,
titleContentColor = titleContentColor,
textContentColor = textContentColor,
tonalElevation = tonalElevation,
properties = properties
)
}
Also, do not forget to add correct android:windowSoftInputMode
in Manifest: android:windowSoftInputMode="adjustResize"
Now you can use TrickyDialog
instead of AlertDialog
. Again, this solution is not elegant. But maybe it will be helpful for someone who faced the same issue. Also, this solution will not work properly for Landscape Screen Orientation.