Skip to content

Commit e8cbbba

Browse files
author
Alexander Matečný
committed
Properly handle action's height being larger than available content height
1 parent c6bdf86 commit e8cbbba

File tree

1 file changed

+54
-16
lines changed
  • ui/src/androidMain/kotlin/kiwi/orbit/compose/ui/controls

1 file changed

+54
-16
lines changed

ui/src/androidMain/kotlin/kiwi/orbit/compose/ui/controls/Scaffold.kt

+54-16
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ import androidx.compose.foundation.layout.ime
1414
import androidx.compose.foundation.layout.isImeVisible
1515
import androidx.compose.foundation.layout.systemBars
1616
import androidx.compose.foundation.layout.union
17+
import androidx.compose.foundation.layout.wrapContentSize
1718
import androidx.compose.runtime.Composable
1819
import androidx.compose.runtime.remember
20+
import androidx.compose.ui.Alignment
1921
import androidx.compose.ui.Modifier
2022
import androidx.compose.ui.graphics.Brush
2123
import androidx.compose.ui.graphics.Color
@@ -91,31 +93,27 @@ private fun ScaffoldLayout(
9193
val looseConstraints = constraints.copy(minWidth = 0, minHeight = 0)
9294

9395
val topBarPlaceables = subcompose(SlotTopAppBar, topBar).map { it.measure(looseConstraints) }
94-
val actionPlaceables = subcompose(SlotAction, action).map { it.measure(looseConstraints) }
95-
val toastPlaceables = subcompose(SlotToast, toast).map { it.measure(looseConstraints) }
96+
val topBarHeight = topBarPlaceables.maxOfOrNull { it.height } ?: 0
9697

98+
val maxActionHeight = layoutHeight - topBarHeight
99+
val actionConstraints = looseConstraints.copy(maxHeight = maxActionHeight)
100+
val actionPlaceables = subcompose(SlotAction, action).map { it.measure(actionConstraints) }
97101
val actionHeight = actionPlaceables.maxOfOrNull { it.height } ?: 0
98102
val actionFadeHeight = actionPlaceables.firstOrNull()?.get(ActionFadeLine)?.let { value ->
99103
if (value == AlignmentLine.Unspecified) 0 else value
100104
} ?: 0
101105

102106
val contentInsets = contentWindowInsets.asPaddingValues(this)
103-
val contentTop = topBarPlaceables.maxOfOrNull { it.height } ?: 0
104-
val contentBottom = if (actionHeight > 0) {
107+
val occupiedBottomSize = if (actionHeight > 0) {
105108
(actionHeight - actionFadeHeight).coerceAtLeast(0)
106109
} else {
107-
if (imeOpened) {
108-
contentInsets.calculateBottomPadding().roundToPx()
109-
} else {
110-
0
111-
}
110+
if (imeOpened) contentInsets.calculateBottomPadding().roundToPx() else 0
112111
}
113112
val contentConstraints = looseConstraints.copy(
114-
maxHeight = layoutHeight - contentTop - contentBottom,
113+
maxHeight = layoutHeight - topBarHeight - occupiedBottomSize,
115114
)
116-
117115
val innerPadding = PaddingValues(
118-
top = if (contentTop > 0) {
116+
top = if (topBarHeight > 0) {
119117
0.dp
120118
} else {
121119
contentInsets.calculateTopPadding()
@@ -136,11 +134,13 @@ private fun ScaffoldLayout(
136134
content(innerPadding)
137135
}.map { it.measure(contentConstraints) }
138136

137+
val toastPlaceables = subcompose(SlotToast, toast).map { it.measure(looseConstraints) }
138+
139139
layout(layoutWidth, layoutHeight) {
140-
contentPlaceables.forEach { it.placeRelative(0, contentTop) }
140+
contentPlaceables.forEach { it.placeRelative(0, topBarHeight) }
141141
topBarPlaceables.forEach { it.placeRelative(0, 0) }
142142
actionPlaceables.forEach { it.placeRelative(0, layoutHeight - actionHeight) }
143-
toastPlaceables.forEach { it.placeRelative(0, contentTop) }
143+
toastPlaceables.forEach { it.placeRelative(0, topBarHeight) }
144144
}
145145
}
146146
}
@@ -174,15 +174,17 @@ public fun ScaffoldAction(
174174
},
175175
) { measurables, constraints ->
176176
val padding = 16.dp.roundToPx()
177+
val top = fadeHeight.roundToPx()
177178
val action = measurables.first().measure(
178-
constraints.offset(horizontal = padding * -2),
179+
constraints
180+
.offset(horizontal = padding * -2)
181+
.copy(maxHeight = (constraints.maxHeight - padding - top).coerceAtLeast(0)),
179182
)
180183

181184
if (action.height == 0) {
182185
return@Layout layout(0, 0) {}
183186
}
184187

185-
val top = fadeHeight.roundToPx()
186188
val width = constraints.maxWidth
187189
val height = top + action.height + padding + inset.calculateBottomPadding().roundToPx()
188190

@@ -220,3 +222,39 @@ internal fun ScaffoldPreview() {
220222
}
221223
}
222224
}
225+
226+
@OrbitPreviews
227+
@Composable
228+
internal fun ScaffoldPreviewWithFullScreenAction() {
229+
Preview {
230+
Scaffold(
231+
topBar = {
232+
TopAppBar(title = { Text(text = "Title") })
233+
},
234+
action = {
235+
Box(
236+
modifier = Modifier
237+
.fillMaxSize()
238+
.background(OrbitTheme.colors.surface.normal),
239+
) {
240+
Text(
241+
text = "Custom full screen action",
242+
modifier = Modifier
243+
.fillMaxSize()
244+
.wrapContentSize(),
245+
)
246+
ButtonPrimary(
247+
onClick = {},
248+
modifier = Modifier
249+
.fillMaxWidth()
250+
.align(Alignment.BottomCenter),
251+
) {
252+
Text("Custom full screen action")
253+
}
254+
}
255+
},
256+
) {
257+
CustomPlaceholder(Modifier.fillMaxSize())
258+
}
259+
}
260+
}

0 commit comments

Comments
 (0)