Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jetpack Compose - imePadding() for AlertDialog

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:

enter image description here

I am not able to interact with several last items in list because Keyboard covers it.

like image 386
Pasha Oleynik Avatar asked Sep 06 '25 03:09

Pasha Oleynik


2 Answers

As of Compose UI 1.3.0-beta01, you can set DialogProperties.decorFitsSystemWindows to false and imePadding() will work.

https://issuetracker.google.com/issues/229378542 https://developer.android.com/jetpack/androidx/releases/compose-ui#1.3.0-beta01

AlertDialog(
     modifier = Modifier.imePadding(),
     properties = DialogProperties(decorFitsSystemWindows = false),
     onDismissRequest = {
         // ...
     },
     title = {
         // ...
     },
     text = {
         // ...
     },
     confirmButton = {
         // ..
     },
)
like image 121
TheWanderer Avatar answered Sep 07 '25 21:09

TheWanderer


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.

enter image description here

like image 21
Pasha Oleynik Avatar answered Sep 07 '25 21:09

Pasha Oleynik