Reputation: 473
How to position alert dialog in Jetpack Compose to the bottom of the screen. Also, set transparent background.
Upvotes: 15
Views: 12192
Reputation: 411
To avoid breaking the Dialog behaviour dismissOnClickOutside
Do:
@Composable
fun YourDialog(onDismissRequest: () -> Unit) {
Dialog(
onDismissRequest = {
onDismissRequest()
},
DialogProperties(usePlatformDefaultWidth = false), // Full width dialog
) {
EditDialogWindow()
Content(onDismissRequest)// you can apply Modifier.clickable{ onDismissReques } on your Dialog content
}
}
@Composable
fun EditDialogWindow() {
val dialogWindowProvider = LocalView.current.parent as? DialogWindowProvider
dialogWindowProvider?.window?.let { window ->
window.setGravity(Gravity.BOTTOM) // Position your dialog
window.setDimAmount(0f) // Extra: Remove black background of Dialog
}
}
You can modify the gravity with as you wish:
// Extra: How to add multiple positions? window.setGravity(Gravity.BOTTOM or Gravity.END)
Upvotes: 1
Reputation: 2603
FYI, one easy way to get a dialog with padding (as well as alignment) without compromising 'dismiss on click outside' (a problem with an align-in-a-Box
solution):
fun MyTopAlignedDialog(
onDismissRequest: () -> Unit,
) {
Dialog(
onDismissRequest = onDismissRequest,
//...
) {
(LocalView.current.parent as DialogWindowProvider).apply {
window.setGravity(Gravity.TOP)
window.attributes = window.attributes.apply {
y = DialogTopPadding
}
}
// Dialog content...
}
}
internal const val DialogTopPadding = 192
Upvotes: 1
Reputation: 609
The solution that worked best for me, getting the idea from Vladimir's response, is to get a reference to the window from within the Dialog and set the desired gravity.
Dialog(
onDismissRequest = [...],
properties = [...],
) {
val dialogWindowProvider = LocalView.current.parent as DialogWindowProvider
dialogWindowProvider.window.setGravity(Gravity.BOTTOM)
[...]
}
The cast shouldn't be an issue but, of course, it could be safe-casted to prevent unpleasant surprises.
Upvotes: 23
Reputation: 84
The solution provided by @Rameshbabu changes the position of the dialog as expected. However, as was mentioned in the comments the dialog consequently becomes "fullscreen" and it can't be dismissed by tapping on the overlay.
I found another tricky solution. You can copy the source code of androidx.compose.ui.window.AndroidDialog.kt
which comes with "androidx.compose.ui"
. By doing this you'll be able to access the dialog's window directly and change its gravity and other parameters.
The simplest way would be to add some code in the androidx.compose.ui.window.DialogWrapper
class. For example in the init function:
private class DialogWrapper(
private var onDismissRequest: () -> Unit,
...
) : Dialog(ContextThemeWrapper(...){
...
init {
val window = window ?: error("Dialog has no window")
window.requestFeature(Window.FEATURE_NO_TITLE)
window.setBackgroundDrawableResource(android.R.color.transparent)
window.setGravity(Gravity.TOP) // This to be added
Hopefully, the Jetpack Compose team will make the compose Dialog more customizable in the future.
Upvotes: -1
Reputation: 473
Thanks, @alekseyHunter & @johann. I can able to achieve this with custom layout modifier.
Custom modifier to position alert dialog
enum class CustomDialogPosition {
BOTTOM, TOP
}
fun Modifier.customDialogModifier(pos: CustomDialogPosition) = layout { measurable, constraints ->
val placeable = measurable.measure(constraints);
layout(constraints.maxWidth, constraints.maxHeight){
when(pos) {
CustomDialogPosition.BOTTOM -> {
placeable.place(0, constraints.maxHeight - placeable.height, 10f)
}
CustomDialogPosition.TOP -> {
placeable.place(0,0,10f)
}
}
}
}
And in alert dialog implementation as
AlertDialog( ..., modifiers = Modifiers.customDialogModifier(CustomDialogPosition.BOTTOM))
{
// block
})
Upvotes: 10
Reputation: 418
Look so simple.
Box(Modifier.fillMaxSize()) {
Column() {
/* Content */
}
/* Box alert */
Box(
Modifier
.padding(horizontal = 32.dp, vertical = 16.dp)
.fillMaxWidth()
.background(Color.Transparent, RoundedCornerShape(8.dp))
.border(2.dp, Color.LightGray, RoundedCornerShape(8.dp))
.align(Alignment.BottomCenter)
) {
Text(
text = "Alert",
modifier = Modifier
.padding(16.dp)
.fillMaxWidth(),
textAlign = TextAlign.Center,
color = Color.Black
)
}
}
Upvotes: 0