compose-multiplatform icon indicating copy to clipboard operation
compose-multiplatform copied to clipboard

ExposedDropdownMenu can overlap the textfield

Open m-sasha opened this issue 1 year ago • 5 comments

If the ExposedDropdownMenu is too tall, it will overlap the textfield:

@OptIn(ExperimentalMaterialApi::class)
fun main() = singleWindowApplication {
    Column(Modifier.padding(start = 8.dp)) {
        var expanded by remember { mutableStateOf(false) }
        ExposedDropdownMenuBox(
            expanded = expanded,
            onExpandedChange = { expanded = it}
        ) {
            var text by remember { mutableStateOf("") }
            TextField(
                value = text,
                onValueChange = { text = it },
                modifier = Modifier
                    .size(120.dp, 47.dp)  // Height must be less than 48.dp to reproduce
            )
            ExposedDropdownMenu(
                expanded = expanded,
                onDismissRequest = { expanded = false },
                modifier = Modifier.exposedDropdownSize(true)
            ) {
                repeat(100) {
                    DropdownMenuItem({}) { Text("Item $it") }
                }
            }
        }
    }
}
SCR-20231111-rcqb SCR-20231111-rcqv

Affected platforms

  • All
  • Compose Multiplatform version: 1.5.10

m-sasha avatar Nov 11 '23 17:11 m-sasha

The issue appears to be in the calculation of menuHeight in ExposedDropdownMenuBox:

        modifier.onGloballyPositioned {
            width = it.size.width
            val boundsInWindow = it.boundsInWindow()
            val visibleWindowBounds = windowInfo.containerSize.toIntRect()
            val heightAbove = boundsInWindow.top - visibleWindowBounds.top
            val heightBelow = visibleWindowBounds.height - boundsInWindow.bottom
            menuHeight = max(heightAbove, heightBelow).toInt() - verticalMarginInPx
        }

We're assuming the menu can overlap verticalMarginInPx either at the top or the bottom of the window, but not both. But if the textfield is short enough and close enough to the top of the window, and the menu is tall enough, the "heightBelow" can overlap verticalMarginInPx both at the top and the bottom of the window.

in Android code (androidx-main tip; not yet released) this is done like so:

modifier.onGloballyPositioned {
    anchorCoordinates = it
    anchorWidth = it.size.width
    menuMaxHeight = calculateMaxHeight(
        windowBounds = view.rootView.getWindowBounds(),
        anchorBounds = anchorCoordinates.getAnchorBounds(),
        verticalMargin = verticalMargin,
    )
}

private fun calculateMaxHeight(
    windowBounds: Rect,
    anchorBounds: Rect?,
    verticalMargin: Int,
): Int {
    anchorBounds ?: return 0

    val marginedWindowTop = windowBounds.top + verticalMargin
    val marginedWindowBottom = windowBounds.bottom - verticalMargin
    val availableHeight =
        if (anchorBounds.top > windowBounds.bottom || anchorBounds.bottom < windowBounds.top) {
            (marginedWindowBottom - marginedWindowTop).roundToInt()
        } else {
            val heightAbove = anchorBounds.top - marginedWindowTop
            val heightBelow = marginedWindowBottom - anchorBounds.bottom
            max(heightAbove, heightBelow).roundToInt()
        }

    return max(availableHeight, 0)
}

m-sasha avatar Nov 11 '23 17:11 m-sasha

any updates on this issue? Or maybe extended answer how to fix it by myself?

Kykara4uk avatar May 03 '24 22:05 Kykara4uk

how to fix it

abhishekrr avatar May 11 '24 18:05 abhishekrr

How can I apply the above workaround?

unomonteiro avatar May 31 '24 14:05 unomonteiro

Same issue here. If there are more than a few items in the suggestions list, the whole ExposedDropdownMenu covers the TextField.

radomartinec avatar Jun 17 '24 12:06 radomartinec

This is actually a problem in AOSP. I've reported the bug here: https://issuetracker.google.com/issues/360881340

The real issue is not in our menu height calculation. The dropdown menu should align to the bottom of the text field even if it means going inside the vertical margin. We could improve the situation somewhat by limiting the dropdown height to

visibleWindowBounds.height - 2*verticalMarginInPx

but then the dropdown will look like this:

image

m-sasha avatar Aug 20 '24 10:08 m-sasha

Please comment here when someone knows how to fix this

nordfalk avatar Aug 22 '24 11:08 nordfalk

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.

okushnikov avatar Aug 26 '24 13:08 okushnikov

providing max height can help

ExposedDropdownMenu(modifier = Modifier.heightIn(max = 200.dp) ....

chandresh204 avatar Sep 10 '24 11:09 chandresh204