androiddrop-down-menuandroid-jetpack-composeandroid-dialogandroid-menu

DropdownMenu not aligned to width of Textfield in Dialog composable


The DropdownMenu composable is not aligning to the width of the OutlinedTextField which is inside a Dialog composable. It is shifted slightly to the right. However, placing the DropdownMenu outside the Dialog composable works fine. How can I fix this?

enter image description here

DropdownMenu Composable

@Composable
fun MyDropdownMenu() {
    var mExpanded = rememberSaveable { mutableStateOf(false) }
    var mSelectedText = rememberSaveable { mutableStateOf("") }
    var mTextFieldSize = remember { mutableStateOf(Size.Zero) }
    val mCategories = listOf(
        "Produce",
        "Bakery",
        "Meats",
        "Dairy",
        "Deli",
        "Beverages",
        "Frozen"
    )
    val icon = if (mExpanded.value)
        Icons.Filled.KeyboardArrowUp
    else
        Icons.Filled.KeyboardArrowDown
    Column {

        Box {
            OutlinedTextField(
                value = mSelectedText.value,
                readOnly = true,
                onValueChange = { mSelectedText.value = it },
                label = { Text(text = "Category") },
                trailingIcon = {
                    Icon(icon, null,
                        Modifier.clickable { mExpanded.value = !mExpanded.value })
                },
                modifier = Modifier.onGloballyPositioned { coordinates ->
                mTextFieldSize.value = coordinates.size.toSize()
            }.fillMaxWidth(),
            )

            DropdownMenu(
                expanded = mExpanded.value,
                onDismissRequest = { mExpanded.value = false },
                modifier =  Modifier
                      .width(with(LocalDensity.current) { mTextFieldSize.value.width.toDp()})
            ) {
                mCategories.forEach { label ->
                    DropdownMenuItem(onClick = {
                        mSelectedText.value = label
                        mExpanded.value = false
                    }) {
                        Text(text = label)
                    }
                }
            }

        }
    }


}

Dialog Composable

@Composable
fun AddItemDialog(
    onConfirmClicked: () -> Unit,
    onDismiss: () -> Unit,
) {
    Dialog(
        onDismissRequest = onDismiss
    ) {
        Surface(
            shape = MaterialTheme.shapes.medium,
            color = MaterialTheme.colors.surface,
            modifier = Modifier
                .requiredWidth(LocalConfiguration.current.screenWidthDp.dp * 0.96f)
                .padding(4.dp)
        ) {
            Column(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(top = 16.dp, bottom = 0.dp, start = 16.dp, end = 16.dp)
            ) {
                Text(text = "Add an item", style = MaterialTheme.typography.subtitle1)

                MyDropdownMenu()
                
                Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) {
                    TextButton(onClick = onDismiss) {
                        Text(text = "Cancel")
                    }
                    TextButton(onClick = onConfirmClicked) {
                        Text(text = "OK")
                    }
                }
            }
        }
    }
}

Solution

  • This bug is related to the fact that you're trying to force Dialog to be bigger than it's expected with Modifier.requiredWidth. Visually it works, but DropdownMenu uses alert window size to layout, and this size is smaller than your drawn view.

    There is actually another way to make the dialog view take up the entire width (except for a small padding) that does not cause this bug:

    Dialog(
        onDismissRequest = {  },
        properties = DialogProperties(usePlatformDefaultWidth = false),
    ) {