LazyDsl.kt
/*
* Copyright 2020 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
import androidx.compose.foundation.layout.InnerPadding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@RequiresOptIn(
"This is an experimental API for demonstrating how LazyColumn / LazyRow should work" +
"using a DSL implementation. This is a prototype and its implementation is not suited" +
" for PagedList or large lists."
)
annotation class ExperimentalLazyDsl
/**
* Receiver scope which is used by [LazyColumn] and [LazyRow].
*/
interface LazyListScope {
/**
* Adds a list of items and their content to the scope.
*
* @param items the data list
* @param itemContent the content displayed by a single item
*/
fun <T : Any> items(
items: List<T>,
itemContent: @Composable LazyItemScope.(item: T) -> Unit
)
/**
* Adds a single item to the scope.
*
* @param content the content of the item
*/
fun item(content: @Composable LazyItemScope.() -> Unit)
/**
* Adds a list of items to the scope where the content of an item is aware of its index.
*
* @param items the data list
* @param itemContent the content displayed by a single item
*/
fun <T : Any> itemsIndexed(
items: List<T>,
itemContent: @Composable LazyItemScope.(index: Int, item: T) -> Unit
)
}
private class LazyListScopeImpl : LazyListScope {
// TODO: Avoid allocating per-item composable by saving the composable for a range of items
val allItemsContent = mutableListOf<@Composable LazyItemScope.() -> Unit>()
override fun <T : Any> items(
items: List<T>,
itemContent: @Composable LazyItemScope.(item: T) -> Unit
) {
items.forEach {
allItemsContent.add {
itemContent(it)
}
}
}
override fun item(content: @Composable LazyItemScope.() -> Unit) {
allItemsContent.add(content)
}
override fun <T : Any> itemsIndexed(
items: List<T>,
itemContent: @Composable LazyItemScope.(index: Int, item: T) -> Unit
) {
items.forEachIndexed { index, item -> allItemsContent.add { itemContent(index, item) } }
}
}
/**
* The DSL implementation of a horizontally scrolling list that only composes and lays out the
* currently visible items.
* This API is not stable yet, please consider using [LazyRowFor] instead.
*
* @param modifier the modifier to apply to this layout
* @param contentPadding specify a padding around the whole content
* @param verticalGravity the vertical gravity applied to the items
* @param content the [LazyListScope] which describes the content
*/
@Composable
@ExperimentalLazyDsl
fun LazyRow(
modifier: Modifier = Modifier,
contentPadding: InnerPadding = InnerPadding(0.dp),
verticalGravity: Alignment.Vertical = Alignment.Top,
content: LazyListScope.() -> Unit
) {
val scope = LazyListScopeImpl()
scope.apply(content)
LazyFor(
itemsCount = scope.allItemsContent.size,
modifier = modifier,
contentPadding = contentPadding,
verticalGravity = verticalGravity,
isVertical = false
) { index ->
{
scope.allItemsContent[index].invoke(this)
}
}
}
/**
* The DSL implementation of a vertically scrolling list that only composes and lays out the
* currently visible items.
* This API is not stable yet, please consider using [LazyColumnFor] instead.
*
* @param modifier the modifier to apply to this layout
* @param contentPadding specify a padding around the whole content
* @param horizontalGravity the horizontal gravity applied to the items
* @param content the [LazyListScope] which describes the content
*/
@Composable
@ExperimentalLazyDsl
fun LazyColumn(
modifier: Modifier = Modifier,
contentPadding: InnerPadding = InnerPadding(0.dp),
horizontalGravity: Alignment.Horizontal = Alignment.Start,
content: LazyListScope.() -> Unit
) {
val scope = LazyListScopeImpl()
scope.apply(content)
LazyFor(
itemsCount = scope.allItemsContent.size,
modifier = modifier,
contentPadding = contentPadding,
horizontalGravity = horizontalGravity,
isVertical = true
) { index ->
{
scope.allItemsContent[index].invoke(this)
}
}
}