Merge branch 'feat/scrollable-scaffold' into main

This commit is contained in:
2026-07-17 15:36:21 +02:00
2 changed files with 30 additions and 2 deletions

View File

@@ -46,6 +46,16 @@ import de.jeanlucmakiola.floret.identity.predictiveBack
* unchanged: [actions] adds trailing app-bar items; [snackbarHost] hosts * unchanged: [actions] adds trailing app-bar items; [snackbarHost] hosts
* transient messages; [predictiveBack] (off by default) wires the gesture * transient messages; [predictiveBack] (off by default) wires the gesture
* preview to [onBack] for full-screen surfaces that want it. * preview to [onBack] for full-screen surfaces that want it.
*
* Set [scrollable] to false when [content] brings its own scrolling container.
* The default column scrolls as a whole, which composes every row up front —
* fine for the short lists these surfaces normally hold, but a list long enough
* to need a [androidx.compose.foundation.lazy.LazyColumn] can neither nest one
* inside it (same-axis scrolling throws) nor afford the eager pass. Opting out
* hands [content] a plain, unscrolled column to fill instead; the insets, IME
* padding and bar behaviour are unchanged, so a lazy list simply takes over the
* scrolling and gets the top bar's collapse for free through the shared
* nested-scroll connection.
*/ */
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@@ -55,6 +65,7 @@ fun CollapsingScaffold(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
largeTopBar: Boolean = true, largeTopBar: Boolean = true,
predictiveBack: Boolean = false, predictiveBack: Boolean = false,
scrollable: Boolean = true,
actions: @Composable RowScope.() -> Unit = {}, actions: @Composable RowScope.() -> Unit = {},
snackbarHost: @Composable () -> Unit = {}, snackbarHost: @Composable () -> Unit = {},
content: @Composable ColumnScope.() -> Unit, content: @Composable ColumnScope.() -> Unit,
@@ -112,8 +123,19 @@ fun CollapsingScaffold(
.fillMaxSize() .fillMaxSize()
.background(MaterialTheme.colorScheme.surface) .background(MaterialTheme.colorScheme.surface)
.imePadding() .imePadding()
.then(
if (scrollable) {
Modifier
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
.padding(top = 8.dp, bottom = 24.dp), .padding(top = 8.dp, bottom = 24.dp)
} else {
// The content scrolls itself, so it also owns the edge
// spacing — a lazy list wants it as contentPadding, or
// the first and last rows clip instead of scrolling
// under the bars.
Modifier
},
),
content = content, content = content,
) )
} }

View File

@@ -20,12 +20,17 @@ import androidx.compose.ui.window.DialogWindowProvider
* width without a tall header — it's a short selection list, so the large * width without a tall header — it's a short selection list, so the large
* collapsing header would only be empty space to scroll past. [content] places * collapsing header would only be empty space to scroll past. [content] places
* the connected grouped rows; selecting one calls [onDismiss]. * the connected grouped rows; selecting one calls [onDismiss].
*
* [scrollable] forwards to [CollapsingScaffold]: leave it on unless [content]
* scrolls itself, which a picker only needs for an option list long enough to
* warrant a lazy container.
*/ */
@Composable @Composable
fun FullScreenPicker( fun FullScreenPicker(
title: String, title: String,
onDismiss: () -> Unit, onDismiss: () -> Unit,
predictiveBack: Boolean = false, predictiveBack: Boolean = false,
scrollable: Boolean = true,
actions: @Composable RowScope.() -> Unit = {}, actions: @Composable RowScope.() -> Unit = {},
content: @Composable ColumnScope.() -> Unit, content: @Composable ColumnScope.() -> Unit,
) { ) {
@@ -50,6 +55,7 @@ fun FullScreenPicker(
onBack = onDismiss, onBack = onDismiss,
largeTopBar = false, largeTopBar = false,
predictiveBack = predictiveBack, predictiveBack = predictiveBack,
scrollable = scrollable,
actions = actions, actions = actions,
content = content, content = content,
) )