LazyLayoutState.kt
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.compose.foundation.lazy.layout
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.layout.Remeasurement
import androidx.compose.ui.layout.RemeasurementModifier
import androidx.compose.ui.layout.SubcomposeMeasureScope
/**
* Creates a [LazyLayoutState] that is remembered across recompositions.
*/
@Composable
internal fun rememberLazyLayoutState(): LazyLayoutState {
return remember { LazyLayoutState() }
}
/**
* A state object that can be hoisted to interact and observe the state of the [LazyLayout].
*
* In most cases, this will be created via [rememberLazyLayoutState].
*/
@Stable
internal class LazyLayoutState internal constructor() {
/**
* Information about the layout of the lazy layout, calculated during the latest layout pass.
*/
val layoutInfo: LazyLayoutInfo get() = layoutInfoState.value
/** Backing state for [layoutInfo] */
internal val layoutInfoState = mutableStateOf<LazyLayoutInfo>(EmptyLazyLayoutInfo)
internal var layoutInfoNonObservable: LazyLayoutInfo = EmptyLazyLayoutInfo
/**
* Remeasures the lazy list now. This can be used, for example, in reaction to scrolling.
*/
fun remeasure() = remeasurement?.forceRemeasure()
/**
* The [Remeasurement] object associated with our layout. It allows us to remeasure
* synchronously during scroll.
*/
private var remeasurement: Remeasurement? = null
/**
* The modifier which provides [remeasurement].
*/
internal val remeasurementModifier = object : RemeasurementModifier {
override fun onRemeasurementAvailable(remeasurement: Remeasurement) {
this@LazyLayoutState.remeasurement = remeasurement
}
}
/**
* The items provider of the lazy layout.
*/
internal var itemsProvider: () -> LazyLayoutItemsProvider = { NoItemsProvider }
/**
* Listener to be notified after measurement - the prefetcher.
*/
internal var onPostMeasureListener: LazyLayoutOnPostMeasureListener? = null
}
internal interface LazyLayoutInfo {
/** The items currently participating in the layout of the lazy layout. */
val visibleItemsInfo: List<LazyLayoutItemInfo>
}
private object EmptyLazyLayoutInfo : LazyLayoutInfo {
override val visibleItemsInfo = emptyList<LazyLayoutItemInfo>()
}
internal interface LazyLayoutOnPostMeasureListener {
fun SubcomposeMeasureScope.onPostMeasure(result: LazyLayoutMeasureResult)
}
private object NoItemsProvider : LazyLayoutItemsProvider {
override fun getContent(index: Int): () -> Unit = error("No items")
override val itemsCount = 0
override fun getKey(index: Int): Any = error("No items")
}