アプリ開発備忘録

PlayStationMobile、Android、UWPの開発備忘録

【Jetpack Compose】CoordinatorLayoutのCollapsingを作る

こういうのを作ります。

コード

@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
) {}