前人未踏の領域へ Androidアプリ開発編

Androidアプリ開発に関する調査メモ置き場。古い記事にはアプリ以外も含まれます。

Android: LazyVerticalGridでPaging3を使えるようにする

追記

https://developer.android.com/jetpack/androidx/releases/paging#1.0.0-alpha19 1.0.0-alpha19ですべてのLazyLayoutに対して利用可能な低レベルの拡張メソッドが提供されるようになっため、以下の対応はすでに不要となっている。

内容

LazyVerticalGridでPaging3のandroidx.paging.compose.LazyPagingItems を使いたいが、LazyListScope.items()に相当するものがLazyGridScopeになぜか存在しない(paging-compose:1.0.0-alpha16時点)。どうすればいいか。

対応

もともとのLazyListScope.items()自体がLazyListScopeに関数を拡張したものなので、同じものをLazyGridScopeに対しても作ってみることにする。ほとんどLazyListScope.items()のコピペ。

// LazyPagingGridItems.ktを自作

/**
 * [LazyListScope.items]の[LazyGridScope]版。
 */
fun <T : Any> LazyGridScope.items(
    items: LazyPagingItems<T>,
    key: ((item: T) -> Any)? = null,
    span: (LazyGridItemSpanScope.(item: T) -> GridItemSpan)? = null,
    itemContent: @Composable LazyGridItemScope.(value: T?) -> Unit
) {
    items(
        count = items.itemCount,
        key = if (key == null) null else { index ->
            val item = items.peek(index)
            if (item == null) {
                PagingPlaceholderKey(index)
            } else {
                key(item)
            }
        },
       span = if (span != null) { { span(items[it]!!) } } else null
    ) { index ->
        itemContent(items[index])
    }
}

fun <T : Any> LazyGridScope.itemsIndexed(
    items: LazyPagingItems<T>,
    key: ((index: Int, item: T) -> Any)? = null,
    span: (LazyGridItemSpanScope.(index: Int, item: T) -> GridItemSpan)? = null,
    itemContent: @Composable LazyGridItemScope.(index: Int, value: T?) -> Unit
) {
    items(
        count = items.itemCount,
        key = if (key == null) null else { index ->
            val item = items.peek(index)
            if (item == null) {
                PagingPlaceholderKey(index)
            } else {
                key(index, item)
            }
        },
        span = if (span != null) { { span(it, items[it]!!) } } else null,
    ) { index ->
        itemContent(index, items[index])
    }
}


@SuppressLint("BanParcelableUsage")
private data class PagingPlaceholderKey(private val index: Int) : Parcelable {
    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeInt(index)
    }

    override fun describeContents(): Int {
        return 0
    }

    companion object {
        @Suppress("unused")
        @JvmField
        val CREATOR: Parcelable.Creator<PagingPlaceholderKey> =
            object : Parcelable.Creator<PagingPlaceholderKey> {
                override fun createFromParcel(parcel: Parcel) =
                    PagingPlaceholderKey(parcel.readInt())

                override fun newArray(size: Int) = arrayOfNulls<PagingPlaceholderKey?>(size)
            }
    }
}

とりあえずこれで動く。いずれライブラリのバージョンが上がれば本家から提供されると思う。 LazyColumnでPagingDataを使う記事を書いてないのにLazyVerticalGridの記事書いちゃってるので色々と使い方とか前提の話がぶっ飛んでますがご了承下さい。