Skip to content

Commit

Permalink
Fix ExposedDropdownMenuBox recomposing unnecessarily (#1156)
Browse files Browse the repository at this point in the history
  • Loading branch information
m-sasha committed Mar 4, 2024
1 parent e26d5f5 commit ba6482c
Show file tree
Hide file tree
Showing 2 changed files with 517 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,21 @@ package androidx.compose.material3
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.width
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.layout.LayoutCoordinates
import androidx.compose.ui.layout.boundsInWindow
import androidx.compose.ui.layout.layout
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalWindowInfo
import androidx.compose.ui.platform.debugInspectorInfo
import androidx.compose.ui.unit.constrainHeight
import androidx.compose.ui.unit.constrainWidth
import androidx.compose.ui.unit.toIntRect
Expand Down Expand Up @@ -87,24 +81,24 @@ actual fun ExposedDropdownMenuBox(
) {
val density = LocalDensity.current
val windowInfo = LocalWindowInfo.current
var width by remember { mutableIntStateOf(0) }
var menuHeight by remember { mutableIntStateOf(0) }
var anchorWidth by remember { mutableIntStateOf(0) }
var menuMaxHeight by remember { mutableIntStateOf(0) }
val verticalMarginInPx = with(density) { MenuVerticalMargin.roundToPx() }

val focusRequester = remember { FocusRequester() }
val expandedDescription = getString(Strings.MenuExpanded)
val collapsedDescription = getString(Strings.MenuCollapsed)

val scope = remember(expanded, onExpandedChange, density, menuHeight, width) {
val scope = remember(expanded, onExpandedChange, windowInfo, density) {
object : ExposedDropdownMenuBoxScope() {
override fun Modifier.menuAnchor(): Modifier = this
.onGloballyPositioned {
width = it.size.width
anchorWidth = 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
menuMaxHeight = max(heightAbove, heightBelow).toInt() - verticalMarginInPx
}
.expandable(
expanded = expanded,
Expand All @@ -114,17 +108,19 @@ actual fun ExposedDropdownMenuBox(
)
.focusRequester(focusRequester)

override fun Modifier.exposedDropdownSize(matchTextFieldWidth: Boolean): Modifier {
return with(density) {
heightIn(max = menuHeight.toDp()).let {
if (matchTextFieldWidth) {
it.width(width.toDp())
} else {
it
}
override fun Modifier.exposedDropdownSize(matchTextFieldWidth: Boolean): Modifier =
layout { measurable, constraints ->
val menuWidth = constraints.constrainWidth(anchorWidth)
val menuConstraints = constraints.copy(
maxHeight = constraints.constrainHeight(menuMaxHeight),
minWidth = if (matchTextFieldWidth) menuWidth else constraints.minWidth,
maxWidth = if (matchTextFieldWidth) menuWidth else constraints.maxWidth,
)
val placeable = measurable.measure(menuConstraints)
layout(placeable.width, placeable.height) {
placeable.place(0, 0)
}
}
}
}
}

Expand Down

0 comments on commit ba6482c

Please sign in to comment.