First confirm that recomposition is associated with expensive work or missed frames. A recomposition count alone is not a performance verdict.
If the top-level screen reads every scroll offset to position one header, that read can invalidate a much wider composition scope than necessary. When only placement changes, a lambda-based placement modifier can read the value later.
For a header that intentionally tracks a ScrollState offset:
Box(
modifier = Modifier.offset {
IntOffset(x = 0, y = -scrollState.value)
}
) {
HeaderContent()
}
The offset is read inside the placement lambda. Reading scrollState.value earlier into a local variable and capturing that value would preserve the earlier observation. Apply this to a suitable layout; it is not a complete collapsing-toolbar implementation.
If scrolling changes which content exists, composition must do work. If the only decision is whether to show a “back to top” button, derived state can reduce changes to a threshold crossing instead of each pixel. Avoid wrapping every expression in derivedStateOf; it has its own cost.
How do you verify the improvement? Run the same scroll journey on a release-like build, compare frame timing, and inspect the trace. Also check header placement, touch behavior, and accessibility after the change.
Mark this when you can explain the answer in your own words.
Help fellow developers prepare for interviews
Sharing helps the Android community grow 💚