こういうのを作ります。
コード
@Composable public fun CollapsingLayout( modifier: Modifier = Modifier, scrollOffset: () -> Int, content: @Composable () -> Unit ) { Layout( modifier = modifier.clip(RectangleShape), content = content ) { measurables, constraints -> if (measurables.size > 1) throw IllegalArgumentException("content item must have only.") val viewWidth = constraints.maxWidth val viewHeight = constraints.maxHeight val view = measurables[0].measure(constraints.copy(maxHeight = Int.MAX_VALUE)) val putY = (viewHeight - view.height) * 0.5 layout(viewWidth, viewHeight) { view.place( x = 0, y = ( min(0, putY.toInt()) + (scrollOffset() * 0.5) ).toInt(), ) } } }
Preview
@Preview @Composable private fun Preview() { val state = rememberLazyListState() LazyColumn(state = state) { item { CollapsingLayout( modifier = Modifier.height(300.dp), scrollOffset = { state.firstVisibleItemScrollOffset } ) { Box( modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center, ) { Text(text = "テキスト", fontSize = 80.sp) Column( modifier = Modifier .fillMaxWidth() .wrapContentHeight() ) { Spacer( modifier = Modifier .fillMaxWidth() .height(100.dp) .background(Color.Blue) ) Spacer( modifier = Modifier .fillMaxWidth() .height(100.dp) .background(Color.Green) ) Spacer( modifier = Modifier .fillMaxWidth() .height(100.dp) .background(Color.Red) ) Spacer( modifier = Modifier .fillMaxWidth() .height(100.dp) .background(Color.Cyan) ) } } } } item { Spacer( modifier = Modifier .fillMaxWidth() .height(1000.dp) .background(Color.Yellow) ) } } }
補足説明
scrollOffset
をLambdaで渡すことによってCompositionをスキップして、Layoutフェーズだけを実行することができます。
https://developer.android.com/jetpack/compose/phases
@Composable public fun CollapsingLayout( modifier: Modifier = Modifier, scrollOffset: () -> Int, content: @Composable () -> Unit ) {}