🚀

JetpackCompose CoordinatorLayoutを実装してみる

2022/12/13に公開

環境

composeVersion = 1.3.0

composeでCoordinatorLayoutみたいなものを作る時の問題

  • 実直に作ろうとするとxmlで作るよりもややこしくなる
  • pagerと組み合わせることがほぼできない

この2点が大きく両方を実現することがほぼできないです。

pagerを諦めるのであれば基本的に

https://developer.android.com/jetpack/compose/lists?hl=ja#sticky-headers

こちらを使うと簡単に実装できる印象ではあります。


ではどう作るかという話になりますが

結論composeに固執するのは諦めてxmlで作ろうという話になります

サンプルコード

xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <!-- スクロール時に画面外に消える要素を描画する領域 -->
        <androidx.compose.ui.platform.ComposeView
            android:id="@+id/header_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_scrollFlags="scroll|enterAlwaysCollapsed" />

        <!-- スクロールしても画面内に残る領域 -->
        <androidx.compose.ui.platform.ComposeView
            android:id="@+id/toolbar_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </com.google.android.material.appbar.AppBarLayout>

    <!-- 画面全体に配置するスクロール可能なコンテンツを描画する領域 -->
    <androidx.compose.ui.platform.ComposeView
        android:id="@+id/main_content"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>
compose

@Composable
fun CoordinatorLayout(
    invisibleHeader: @Composable () -> Unit,
    toolbar: @Composable () -> Unit,
    mainContent: @Composable () -> Unit
) {
    AndroidView(
        factory = { context ->
            View.inflate(context, R.layout.coordinator_layout, null)
        },
        update = { layout ->
            with(layout.findViewById<ComposeView>(R.id.header_content)) {
                setContent(invisibleHeader)
            }
            with(layout.findViewById<ComposeView>(R.id.toolbar_content)) {
                setContent(toolbar)
            }
            with(layout.findViewById<ComposeView>(R.id.main_content)) {
                setContent(mainContent)
            }
        }
    )
}

解説

解説も何もxmlで作ってそれをcomposeと併用するという話で

https://blog.covelline.com/entry/2022/06/22/173922

ほぼこちらの引用になります。


一つ注意なのは元記事のものはfactory内に記述されてしまっているので

情報の更新が起きた際に画面の更新が起きません


なのでupdateの返り値にfactoryで作ったlayoutが返ってくるので

そちらを使って作成しようということになります。


将来的にfullComposeで簡単に書ける方法が実装されると嬉しいのですが

当分は無理そうなので無理な時はcomposeに固執せず

xmlと併用する方向で考えていくといいかもしれないですね。

参考記事

https://blog.covelline.com/entry/2022/06/22/173922

https://qiita.com/iwata-n/items/e7c5e8db0f9fbb8c288b

https://developer.android.com/jetpack/compose/gestures?hl=ja#nested-scrolling

https://developer.android.com/jetpack/compose/lists?hl=ja#avoid-nesting-scrollable

https://www.geeksforgeeks.org/nested-scrolling-in-android-using-jetpack-compose/

https://matsudamper.hatenablog.com/entry/2022/06/09/131151

https://google.github.io/accompanist/pager/

Discussion