BeyondBoundsLayout.kt
/*
* Copyright 2022 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.ui.layout
import androidx.compose.ui.modifier.ProvidableModifierLocal
import androidx.compose.ui.modifier.modifierLocalOf
import kotlin.jvm.JvmInline
/**
* A modifier local that provides access to a [BeyondBoundsLayout] that a child can use to
* ask a parent to layout more items that are beyond its visible bounds.
*/
val ModifierLocalBeyondBoundsLayout: ProvidableModifierLocal<BeyondBoundsLayout?> =
modifierLocalOf { null }
/**
* Layout extra items in the specified direction.
*
* A [BeyondBoundsLayout] instance can be obtained by consuming the
* [BeyondBoundsLayout modifier local][ModifierLocalBeyondBoundsLayout].
* It can be used to send a request to layout more items in a particular
* [direction][LayoutDirection]. This can be useful when composition or layout is determined lazily,
* as with a LazyColumn. The request is received by any parent up the hierarchy that provides this
* modifier local.
*/
interface BeyondBoundsLayout {
/**
* Send a request to layout more items in the specified
* [direction][LayoutDirection]. The request is received by a parent up the
* hierarchy. The parent adds one item at a time and calls [block] after each item is added.
* The parent continues adding new items as long as [block] returns null. Once you have all
* the items you need, you can perform some operation and return a non-null value. Returning
* this value stops the laying out of beyond bounds items. (Note that you have to return a
* non-null value stop iterating).
*
* @param direction The direction from the visible bounds in which more items are requested.
* @param block Continue to layout more items until this block returns a non null item.
* @return The value returned by the last run of [block]. If we layout all the available
* items then the returned value is null. When this function returns all the beyond bounds items
* may be disposed. Therefore you have to perform any custom logic within the [block] and return
* the value you need.
*/
fun <T> layout(
direction: LayoutDirection,
block: BeyondBoundsScope.() -> T?
): T?
/**
* The scope used in [BeyondBoundsLayout.layout].
*/
interface BeyondBoundsScope {
/**
* Whether we have more content to lay out in the specified direction.
*/
val hasMoreContent: Boolean
}
/**
* The direction (from the visible bounds) that a [BeyondBoundsLayout] is requesting more items
* to be laid.
*/
@JvmInline
value class LayoutDirection internal constructor(
@Suppress("unused") private val value: Int
) {
companion object {
/**
* Direction used in [BeyondBoundsLayout.layout] to request the layout of extra items
* before the current bounds.
*/
val Before = LayoutDirection(1)
/**
* Direction used in [BeyondBoundsLayout.layout] to request the layout of extra items
* after the current bounds.
*/
val After = LayoutDirection(2)
/**
* Direction used in [BeyondBoundsLayout.layout] to request the layout of extra items
* to the left of the current bounds.
*/
val Left = LayoutDirection(3)
/**
* Direction used in [BeyondBoundsLayout.layout] to request the layout of extra items
* to the right of the current bounds.
*/
val Right = LayoutDirection(4)
/**
* Direction used in [BeyondBoundsLayout.layout] to request the layout of extra items
* above the current bounds.
*/
val Above = LayoutDirection(5)
/**
* Direction used in [BeyondBoundsLayout.layout] to request the layout of extra items
* below the current bounds.
*/
val Below = LayoutDirection(6)
}
override fun toString(): String = when (this) {
Before -> "Before"
After -> "After"
Left -> "Left"
Right -> "Right"
Above -> "Above"
Below -> "Below"
else -> "invalid LayoutDirection"
}
}
}