From c49c232c52bbb2e9d6ba553f8807cf8b33555813 Mon Sep 17 00:00:00 2001 From: Flaringapp Date: Sun, 5 Apr 2026 11:17:46 +0300 Subject: [PATCH 1/3] Cleanup sample vertical fading edge --- .../ui/samples/common/SampleVerticalFadingEdge.kt | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/common/SampleVerticalFadingEdge.kt b/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/common/SampleVerticalFadingEdge.kt index 66cb79f..26d2de9 100644 --- a/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/common/SampleVerticalFadingEdge.kt +++ b/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/common/SampleVerticalFadingEdge.kt @@ -20,16 +20,16 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color -import androidx.compose.ui.layout.layout import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp import com.flaringapp.compose.topbar.sample.shared.ui.theme.ComposeCollapsingTopBarTheme @@ -47,13 +47,9 @@ fun SampleVerticalFadingEdge( Box( modifier = modifier - .layout { measurable, constraints -> - val placeable = measurable.measure(constraints) - layout(placeable.width, 0) { - placeable.place(IntOffset.Zero) - } - } .fillMaxWidth() + .height(0.dp) + .wrapContentHeight(Alignment.Top, unbounded = true) .height(height) .background(brush), ) From 5665d331d5e98a86fc1279eddb46744972c92c5d Mon Sep 17 00:00:00 2001 From: Flaringapp Date: Sun, 5 Apr 2026 11:30:23 +0300 Subject: [PATCH 2/3] wip --- AGENTS.md | 1 + .../api/ComposeCollapsingTopBar.klib.api | 1 + .../CollapsingTopBarVerticalFadingEdge.kt | 45 ++++++++++--------- .../AlternatelyCollapsibleColumnSample.kt | 6 ++- .../column/FullyCollapsibleColumnSample.kt | 7 ++- .../PartiallyCollapsibleColumnSample.kt | 7 ++- 6 files changed, 41 insertions(+), 26 deletions(-) rename sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/common/SampleVerticalFadingEdge.kt => ComposeCollapsingTopBar/src/commonMain/kotlin/com/flaringapp/compose/topbar/decoration/CollapsingTopBarVerticalFadingEdge.kt (60%) diff --git a/AGENTS.md b/AGENTS.md index 5e61d19..c2623c7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -46,6 +46,7 @@ Use the Gradle wrapper from the repo root: Minimum expectation for most code changes: - Run `./gradlew :sample:android:assembleDebug ktlintCheck checkLegacyAbi` when feasible. +- For Compose API or implementation changes, also run the relevant Compose lint task for each changed module, for example `./gradlew :ComposeCollapsingTopBar:compileLint` or the corresponding sample-module lint task when changes are made there. - For public API changes, pay special attention to `checkLegacyAbi` and the `.klib.api` snapshot. - For behavior changes, validate through the sample app, especially `sample/shared/` and the Android sample shell. diff --git a/ComposeCollapsingTopBar/api/ComposeCollapsingTopBar.klib.api b/ComposeCollapsingTopBar/api/ComposeCollapsingTopBar.klib.api index e7cc17c..e861ae6 100644 --- a/ComposeCollapsingTopBar/api/ComposeCollapsingTopBar.klib.api +++ b/ComposeCollapsingTopBar/api/ComposeCollapsingTopBar.klib.api @@ -323,6 +323,7 @@ final fun (androidx.compose.ui/Modifier).com.flaringapp.compose.topbar.dependent final fun (androidx.compose.ui/Modifier).com.flaringapp.compose.topbar.dependent/collapsingTopBarExitStateConnection(com.flaringapp.compose.topbar/CollapsingTopBarState, com.flaringapp.compose.topbar.dependent/CollapsingTopBarExitState): androidx.compose.ui/Modifier // com.flaringapp.compose.topbar.dependent/collapsingTopBarExitStateConnection|collapsingTopBarExitStateConnection@androidx.compose.ui.Modifier(com.flaringapp.compose.topbar.CollapsingTopBarState;com.flaringapp.compose.topbar.dependent.CollapsingTopBarExitState){}[0] final fun (com.flaringapp.compose.topbar/CollapsingTopBarScope).com.flaringapp.compose.topbar.nestedcollapse/CollapsingTopBarColumn(com.flaringapp.compose.topbar/CollapsingTopBarState, androidx.compose.ui/Modifier?, com.flaringapp.compose.topbar.nestedcollapse/CollapsingTopBarColumnDirection?, kotlin/Function3, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // com.flaringapp.compose.topbar.nestedcollapse/CollapsingTopBarColumn|CollapsingTopBarColumn@com.flaringapp.compose.topbar.CollapsingTopBarScope(com.flaringapp.compose.topbar.CollapsingTopBarState;androidx.compose.ui.Modifier?;com.flaringapp.compose.topbar.nestedcollapse.CollapsingTopBarColumnDirection?;kotlin.Function3;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0] final fun <#A: kotlin/Any?> (com.flaringapp.compose.topbar.nestedscroll/CollapsingTopBarNestedScrollStrategy<#A>).com.flaringapp.compose.topbar.nestedscroll/rememberNestedScrollConnection(#A, androidx.compose.foundation.gestures/FlingBehavior?, com.flaringapp.compose.topbar.snap/CollapsingTopBarSnapBehavior?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int): androidx.compose.ui.input.nestedscroll/NestedScrollConnection // com.flaringapp.compose.topbar.nestedscroll/rememberNestedScrollConnection|rememberNestedScrollConnection@com.flaringapp.compose.topbar.nestedscroll.CollapsingTopBarNestedScrollStrategy<0:0>(0:0;androidx.compose.foundation.gestures.FlingBehavior?;com.flaringapp.compose.topbar.snap.CollapsingTopBarSnapBehavior?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){0ยง}[0] +final fun com.flaringapp.compose.topbar.decoration/CollapsingTopBarVerticalFadingEdge(androidx.compose.ui.graphics/Color, androidx.compose.ui/Modifier?, androidx.compose.ui.unit/Dp, kotlin/Boolean, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // com.flaringapp.compose.topbar.decoration/CollapsingTopBarVerticalFadingEdge|CollapsingTopBarVerticalFadingEdge(androidx.compose.ui.graphics.Color;androidx.compose.ui.Modifier?;androidx.compose.ui.unit.Dp;kotlin.Boolean;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0] final fun com.flaringapp.compose.topbar.dependent/com_flaringapp_compose_topbar_dependent_CollapsingTopBarExitState$stableprop_getter(): kotlin/Int // com.flaringapp.compose.topbar.dependent/com_flaringapp_compose_topbar_dependent_CollapsingTopBarExitState$stableprop_getter|com_flaringapp_compose_topbar_dependent_CollapsingTopBarExitState$stableprop_getter(){}[0] final fun com.flaringapp.compose.topbar.dependent/rememberCollapsingTopBarExitState(kotlin/Boolean, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int): com.flaringapp.compose.topbar.dependent/CollapsingTopBarExitState // com.flaringapp.compose.topbar.dependent/rememberCollapsingTopBarExitState|rememberCollapsingTopBarExitState(kotlin.Boolean;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0] final fun com.flaringapp.compose.topbar.nestedcollapse/com_flaringapp_compose_topbar_nestedcollapse_CollapsingTopBarColumnDirection$stableprop_getter(): kotlin/Int // com.flaringapp.compose.topbar.nestedcollapse/com_flaringapp_compose_topbar_nestedcollapse_CollapsingTopBarColumnDirection$stableprop_getter|com_flaringapp_compose_topbar_nestedcollapse_CollapsingTopBarColumnDirection$stableprop_getter(){}[0] diff --git a/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/common/SampleVerticalFadingEdge.kt b/ComposeCollapsingTopBar/src/commonMain/kotlin/com/flaringapp/compose/topbar/decoration/CollapsingTopBarVerticalFadingEdge.kt similarity index 60% rename from sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/common/SampleVerticalFadingEdge.kt rename to ComposeCollapsingTopBar/src/commonMain/kotlin/com/flaringapp/compose/topbar/decoration/CollapsingTopBarVerticalFadingEdge.kt index 26d2de9..e7c4049 100644 --- a/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/common/SampleVerticalFadingEdge.kt +++ b/ComposeCollapsingTopBar/src/commonMain/kotlin/com/flaringapp/compose/topbar/decoration/CollapsingTopBarVerticalFadingEdge.kt @@ -14,35 +14,50 @@ * limitations under the License. */ -package com.flaringapp.compose.topbar.sample.shared.ui.samples.common +package com.flaringapp.compose.topbar.decoration import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.wrapContentHeight -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp -import com.flaringapp.compose.topbar.sample.shared.ui.theme.ComposeCollapsingTopBarTheme +/** + * Draws a vertical fading edge without affecting layout height. + * + * This can be used as an overlay between stacked top bar elements to soften visible overlap while + * keeping surrounding layout positions unchanged. + * + * @param color the opaque edge color that fades to transparent. + * @param modifier the [Modifier] to be applied to this fading edge. + * @param height the visible height of the fading edge. + * @param reverse when `false`, fades from top to bottom; when `true`, fades from bottom to top. + */ @Composable -fun SampleVerticalFadingEdge( +public fun CollapsingTopBarVerticalFadingEdge( + color: Color, modifier: Modifier = Modifier, height: Dp = 12.dp, - color: Color = MaterialTheme.colorScheme.surface, + reverse: Boolean = false, ) { - val brush = remember(color) { - Brush.verticalGradient( - listOf(color, color.copy(alpha = 0f)), - ) + val brush = remember(color, reverse) { + if (reverse) { + Brush.verticalGradient( + listOf(color.copy(alpha = 0f), color), + ) + } else { + Brush.verticalGradient( + listOf(color, color.copy(alpha = 0f)), + ) + } } Box( @@ -54,13 +69,3 @@ fun SampleVerticalFadingEdge( .background(brush), ) } - -@Preview -@Composable -private fun Preview() { - ComposeCollapsingTopBarTheme { - Box(modifier = Modifier.height(40.dp)) { - SampleVerticalFadingEdge() - } - } -} diff --git a/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/column/AlternatelyCollapsibleColumnSample.kt b/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/column/AlternatelyCollapsibleColumnSample.kt index d5d73a3..67c7917 100644 --- a/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/column/AlternatelyCollapsibleColumnSample.kt +++ b/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/column/AlternatelyCollapsibleColumnSample.kt @@ -34,6 +34,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.zIndex +import com.flaringapp.compose.topbar.decoration.CollapsingTopBarVerticalFadingEdge import com.flaringapp.compose.topbar.nestedcollapse.CollapsingTopBarColumn import com.flaringapp.compose.topbar.sample.shared.screen import com.flaringapp.compose.topbar.sample.shared.ui.samples.CollapsingTopBarSample @@ -41,7 +42,6 @@ import com.flaringapp.compose.topbar.sample.shared.ui.samples.common.SampleConte import com.flaringapp.compose.topbar.sample.shared.ui.samples.common.SampleFilterChips import com.flaringapp.compose.topbar.sample.shared.ui.samples.common.SampleTopAppBar import com.flaringapp.compose.topbar.sample.shared.ui.samples.common.SampleTopBarBanner -import com.flaringapp.compose.topbar.sample.shared.ui.samples.common.SampleVerticalFadingEdge import com.flaringapp.compose.topbar.sample.shared.ui.theme.ComposeCollapsingTopBarTheme import com.flaringapp.compose.topbar.scaffold.CollapsingTopBarScaffold import com.flaringapp.compose.topbar.scaffold.CollapsingTopBarScaffoldScrollMode @@ -102,7 +102,9 @@ private fun CollapsingContent( ignoreWindowInsets = true, ) - SampleVerticalFadingEdge() + CollapsingTopBarVerticalFadingEdge( + color = MaterialTheme.colorScheme.surface, + ) SampleFilterChips() FixedElement( diff --git a/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/column/FullyCollapsibleColumnSample.kt b/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/column/FullyCollapsibleColumnSample.kt index 024c729..44f2198 100644 --- a/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/column/FullyCollapsibleColumnSample.kt +++ b/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/column/FullyCollapsibleColumnSample.kt @@ -22,11 +22,13 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import com.flaringapp.compose.topbar.decoration.CollapsingTopBarVerticalFadingEdge import com.flaringapp.compose.topbar.nestedcollapse.CollapsingTopBarColumn import com.flaringapp.compose.topbar.sample.shared.screen import com.flaringapp.compose.topbar.sample.shared.ui.samples.CollapsingTopBarSample @@ -34,7 +36,6 @@ import com.flaringapp.compose.topbar.sample.shared.ui.samples.common.SampleConte import com.flaringapp.compose.topbar.sample.shared.ui.samples.common.SampleFilterChips import com.flaringapp.compose.topbar.sample.shared.ui.samples.common.SampleTopAppBar import com.flaringapp.compose.topbar.sample.shared.ui.samples.common.SampleTopBarBanner -import com.flaringapp.compose.topbar.sample.shared.ui.samples.common.SampleVerticalFadingEdge import com.flaringapp.compose.topbar.sample.shared.ui.theme.ComposeCollapsingTopBarTheme import com.flaringapp.compose.topbar.scaffold.CollapsingTopBarScaffold import com.flaringapp.compose.topbar.scaffold.CollapsingTopBarScaffoldScrollMode @@ -85,7 +86,9 @@ private fun CollapsingContent( ignoreWindowInsets = true, ) - SampleVerticalFadingEdge() + CollapsingTopBarVerticalFadingEdge( + color = MaterialTheme.colorScheme.surface, + ) SampleFilterChips() } }, diff --git a/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/column/PartiallyCollapsibleColumnSample.kt b/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/column/PartiallyCollapsibleColumnSample.kt index 4e216a7..d1ff381 100644 --- a/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/column/PartiallyCollapsibleColumnSample.kt +++ b/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/column/PartiallyCollapsibleColumnSample.kt @@ -21,11 +21,13 @@ import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.only import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import com.flaringapp.compose.topbar.decoration.CollapsingTopBarVerticalFadingEdge import com.flaringapp.compose.topbar.nestedcollapse.CollapsingTopBarColumn import com.flaringapp.compose.topbar.nestedcollapse.CollapsingTopBarColumnDirection import com.flaringapp.compose.topbar.sample.shared.screen @@ -34,7 +36,6 @@ import com.flaringapp.compose.topbar.sample.shared.ui.samples.common.SampleConte import com.flaringapp.compose.topbar.sample.shared.ui.samples.common.SampleFilterChips import com.flaringapp.compose.topbar.sample.shared.ui.samples.common.SampleTopAppBar import com.flaringapp.compose.topbar.sample.shared.ui.samples.common.SampleTopBarBanner -import com.flaringapp.compose.topbar.sample.shared.ui.samples.common.SampleVerticalFadingEdge import com.flaringapp.compose.topbar.sample.shared.ui.theme.ComposeCollapsingTopBarTheme import com.flaringapp.compose.topbar.scaffold.CollapsingTopBarScaffold import com.flaringapp.compose.topbar.scaffold.CollapsingTopBarScaffoldScrollMode @@ -112,7 +113,9 @@ private fun CollapsingContent( onBack = onBack, ) - SampleVerticalFadingEdge() + CollapsingTopBarVerticalFadingEdge( + color = MaterialTheme.colorScheme.surface, + ) SampleFilterChips() } }, From ebcd46fa3e0e41d5e403142915a68f691418b331 Mon Sep 17 00:00:00 2001 From: Flaringapp Date: Sun, 5 Apr 2026 11:57:07 +0300 Subject: [PATCH 3/3] Update readme --- README.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0aace9f..d38863d 100644 --- a/README.md +++ b/README.md @@ -399,7 +399,7 @@ CollapsingTopBarScaffold( SampleTopAppBar( modifier = Modifier.notCollapsible(), ) - SampleVerticalFadingEdge() + CollapsingTopBarVerticalFadingEdge() SampleFilterChips() } }, @@ -544,6 +544,23 @@ CollapsingTopBarScaffold( +### Decorations + +`ComposeCollapsingTopBar` also provides small decoration composables to improve collapsing visuals +in certain scenarios. + +#### Vertical fading edge + +```kotlin +CollapsingTopBarVerticalFadingEdge( + color = MaterialTheme.colorScheme.surface, +) +``` + +`CollapsingTopBarVerticalFadingEdge()` draws a vertical fading overlay with zero layout height. +It's useful for smoothing visible overlap between stacked top bar elements in +`CollapsingTopBarColumn` and regular top bar layouts. + ### React to state changes You can easily access `CollapsingTopBarScaffoldState` and its nested states to observe state