From f55d946fe038e1a12c62e18230e7a246f54f1367 Mon Sep 17 00:00:00 2001 From: onebone Date: Sun, 23 Jan 2022 20:36:12 +0900 Subject: [PATCH 1/2] add align modifier to scaffold body --- .../toolbar/CollapsingToolbarScaffold.kt | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt index 8b6abc7..a47e03d 100644 --- a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt +++ b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt @@ -31,9 +31,12 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.Saver import androidx.compose.runtime.saveable.SaverScope import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.layout.Layout +import androidx.compose.ui.layout.ParentDataModifier +import androidx.compose.ui.unit.Density import kotlin.math.max @Stable @@ -70,6 +73,11 @@ fun rememberCollapsingToolbarScaffoldState( } } +interface CollapsingToolbarScaffoldScope { + @ExperimentalToolbarApi + fun Modifier.align(alignment: Alignment): Modifier +} + @Composable fun CollapsingToolbarScaffold( modifier: Modifier, @@ -78,7 +86,7 @@ fun CollapsingToolbarScaffold( enabled: Boolean = true, toolbarModifier: Modifier = Modifier, toolbar: @Composable CollapsingToolbarScope.() -> Unit, - body: @Composable () -> Unit + body: @Composable CollapsingToolbarScaffoldScope.() -> Unit ) { val flingBehavior = ScrollableDefaults.flingBehavior() @@ -96,7 +104,7 @@ fun CollapsingToolbarScaffold( ) { toolbar() } - body() + CollapsingToolbarScaffoldScopeInstance.body() }, modifier = modifier .then( @@ -146,3 +154,21 @@ fun CollapsingToolbarScaffold( } } } + +internal object CollapsingToolbarScaffoldScopeInstance: CollapsingToolbarScaffoldScope { + @ExperimentalToolbarApi + override fun Modifier.align(alignment: Alignment): Modifier = + this.then(ScaffoldChildAlignmentModifier(alignment)) +} + +private class ScaffoldChildAlignmentModifier( + private val alignment: Alignment +) : ParentDataModifier { + override fun Density.modifyParentData(parentData: Any?): Any { + return (parentData as? ScaffoldParentData) ?: ScaffoldParentData(alignment) + } +} + +data class ScaffoldParentData( + var alignment: Alignment? = null +) From 8ee35f35031b0965fdfcbf4bef4f69ac0e8a99fa Mon Sep 17 00:00:00 2001 From: onebone Date: Sun, 23 Jan 2022 21:16:58 +0900 Subject: [PATCH 2/2] implement placing children with fixed alignment --- .../me/onebone/toolbar/ParallaxActivity.kt | 11 ++++++ .../toolbar/CollapsingToolbarScaffold.kt | 34 ++++++++++++++++--- .../onebone/toolbar/ToolbarWithFabScaffold.kt | 2 +- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/me/onebone/toolbar/ParallaxActivity.kt b/app/src/main/java/me/onebone/toolbar/ParallaxActivity.kt index 934b74a..ad4d80a 100644 --- a/app/src/main/java/me/onebone/toolbar/ParallaxActivity.kt +++ b/app/src/main/java/me/onebone/toolbar/ParallaxActivity.kt @@ -36,6 +36,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.material.Button import androidx.compose.material.Checkbox import androidx.compose.material.MaterialTheme import androidx.compose.material.Surface @@ -120,6 +121,16 @@ fun ParallaxEffect() { ) } } + + @OptIn(ExperimentalToolbarApi::class) + Button( + modifier = Modifier + .padding(16.dp) + .align(Alignment.BottomEnd), + onClick = { } + ) { + Text(text = "Floating Button!") + } } Row( diff --git a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt index a47e03d..dc2671c 100644 --- a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt +++ b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt @@ -37,6 +37,8 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.layout.Layout import androidx.compose.ui.layout.ParentDataModifier import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.IntSize +import androidx.compose.ui.unit.LayoutDirection import kotlin.math.max @Stable @@ -104,6 +106,7 @@ fun CollapsingToolbarScaffold( ) { toolbar() } + CollapsingToolbarScaffoldScopeInstance.body() }, modifier = modifier @@ -115,6 +118,10 @@ fun CollapsingToolbarScaffold( } ) ) { measurables, constraints -> + check(measurables.size >= 2) { + "the number of children should be at least 2: toolbar, (at least one) body" + } + val toolbarConstraints = constraints.copy( minWidth = 0, minHeight = 0 @@ -132,8 +139,14 @@ fun CollapsingToolbarScaffold( ) val toolbarPlaceable = measurables[0].measure(toolbarConstraints) - val bodyPlaceables = - measurables.drop(1).map { it.measure(bodyConstraints) } + + val bodyMeasurables = measurables.subList(1, measurables.size) + val childrenAlignments = bodyMeasurables.mapTo(ArrayList(bodyMeasurables.size)) { + (it.parentData as? ScaffoldParentData)?.alignment + } + val bodyPlaceables = bodyMeasurables.mapTo(ArrayList(bodyMeasurables.size)) { + it.measure(bodyConstraints) + } val toolbarHeight = toolbarPlaceable.height @@ -147,8 +160,19 @@ fun CollapsingToolbarScaffold( ).coerceIn(constraints.minHeight, constraints.maxHeight) layout(width, height) { - bodyPlaceables.forEach { - it.place(0, toolbarHeight + state.offsetY) + bodyPlaceables.forEachIndexed { index, placeable -> + val alignment = childrenAlignments[index] + + if (alignment == null) { + placeable.place(0, toolbarHeight + state.offsetY) + } else { + val offset = alignment.align( + size = IntSize(placeable.width, placeable.height), + space = IntSize(width, height), + layoutDirection = LayoutDirection.Ltr + ) + placeable.place(offset) + } } toolbarPlaceable.place(0, state.offsetY) } @@ -169,6 +193,6 @@ private class ScaffoldChildAlignmentModifier( } } -data class ScaffoldParentData( +private data class ScaffoldParentData( var alignment: Alignment? = null ) diff --git a/lib/src/main/java/me/onebone/toolbar/ToolbarWithFabScaffold.kt b/lib/src/main/java/me/onebone/toolbar/ToolbarWithFabScaffold.kt index 2dd449d..9d3735b 100644 --- a/lib/src/main/java/me/onebone/toolbar/ToolbarWithFabScaffold.kt +++ b/lib/src/main/java/me/onebone/toolbar/ToolbarWithFabScaffold.kt @@ -16,7 +16,7 @@ fun ToolbarWithFabScaffold( toolbar: @Composable CollapsingToolbarScope.() -> Unit, fab: @Composable () -> Unit, fabPosition: FabPosition = FabPosition.End, - body: @Composable () -> Unit + body: @Composable CollapsingToolbarScaffoldScope.() -> Unit ) { SubcomposeLayout( modifier = modifier