👏

Jetpack Compose では同一方向にスクロール可能な Composable をネストできない

2022/02/03に公開1

Android において、同一方向にスクロール可能なコンテンツをネストしたいというのはよくある話です。

具体的には、縦スクロール可能なScrollViewの中にListViewを置くという形ですね。

例えば以下のように、コンテンツ一覧を表示する ComposableListContentsを作成し、それを複数表示する ComposableMultipleListsを作成したいとします。

@Composable
fun MultipleLists(contents1: List<String>, contents2: List<String>) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .verticalScroll(rememberScrollState())
    ) {
        Text(text = "コンテンツ1")
        ListContents(contents = contents1)
        Text(text = "コンテンツ2")
        ListContents(contents = contents2)
    }
}

@Composable
fun ListContents(contents: List<String>) {
    LazyColumn {
        items(contents) {
            Text(text = it)
        }
    }
}

ColumnmodifierverticalScroll(rememberScrollState())を付与し、縦スクロールを可能にしました。

これにより、ListContentsが膨大になってコンテンツが画面に収まりきらなくても、画面全体を縦スクロールして閲覧できるようにしました。

しかし、これを実際に表示しようとすると、下記の例外が出力されます。

java.lang.IllegalStateException: Nesting scrollable in the same direction layouts like LazyColumn and Column(Modifier.verticalScroll()) is not allowed. If you want to add a header before the list of items please take a look on LazyColumn component which has a DSL api which allows to first add a header via item() function and then the list of items via items().

どうやら Jetpack Compose では、LazyColumnLazyRow)またはスクロール可能なColumnRow)はネストできないようです。

解決方法

ListContentsの中身を解体して、以下のようにitemitemsを使って定義するのが良さそうです。

@Composable
fun MultipleLists(contents1: List<String>, contents2: List<String>) {
    LazyColumn(modifier = Modifier.fillMaxSize()) {
        item {
            Text(text = "コンテンツ1")
        }
        items(contents1) {
            Text(text = it)
        }
        item {
            Text(text = "コンテンツ2")
        }
        items(contents2) {
            Text(text = it)
        }
    }
}

一旦これで解決しましたが、他にもっとより良い方法があれば教えてください。

Discussion