1 /* 2 * Copyright 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.compose.foundation.lazy.layout 18 19 import androidx.compose.foundation.ExperimentalFoundationApi 20 import androidx.compose.runtime.Composable 21 import androidx.compose.runtime.Stable 22 23 /** 24 * Provides all the needed info about the items which could be later composed and displayed as 25 * children or [LazyLayout]. 26 * 27 * Note: this interface is a part of [LazyLayout] harness that allows for building custom lazy 28 * layouts. LazyLayout and all corresponding APIs are still under development and are subject to 29 * change. 30 */ 31 @Stable 32 @ExperimentalFoundationApi 33 interface LazyLayoutItemProvider { 34 35 /** The total number of items in the lazy layout (visible or not). */ 36 val itemCount: Int 37 38 /** The item for the given [index] and [key]. */ Itemnull39 @Composable fun Item(index: Int, key: Any) 40 41 /** 42 * Returns the content type for the item on this index. It is used to improve the item 43 * compositions reusing efficiency. Note that null is a valid type and items of such type will 44 * be considered compatible. 45 */ 46 fun getContentType(index: Int): Any? = null 47 48 /** 49 * Returns the key for the item on this index. 50 * 51 * @see getDefaultLazyLayoutKey which you can use if the user didn't provide a key. 52 */ 53 fun getKey(index: Int): Any = getDefaultLazyLayoutKey(index) 54 55 /** 56 * Get index for given key. The index is not guaranteed to be known for all keys in layout for 57 * optimization purposes, but must be present for elements in current viewport. If the key is 58 * not present in the layout or near current viewport, return -1. 59 */ 60 fun getIndex(key: Any): Int = -1 61 } 62 63 /** 64 * Finds a position of the item with the given key in the lists. This logic allows us to detect when 65 * there were items added or removed before our current first item. 66 */ 67 @OptIn(ExperimentalFoundationApi::class) 68 internal fun LazyLayoutItemProvider.findIndexByKey( 69 key: Any?, 70 lastKnownIndex: Int, 71 ): Int { 72 if (key == null || itemCount == 0) { 73 // there were no real item during the previous measure 74 return lastKnownIndex 75 } 76 if (lastKnownIndex < itemCount && key == getKey(lastKnownIndex)) { 77 // this item is still at the same index 78 return lastKnownIndex 79 } 80 val newIndex = getIndex(key) 81 if (newIndex != -1) { 82 return newIndex 83 } 84 // fallback to the previous index if we don't know the new index of the item 85 return lastKnownIndex 86 } 87 88 /** 89 * This creates an object meeting following requirements: 90 * 1) Objects created for the same index are equals and never equals for different indexes. 91 * 2) This class is saveable via a default SaveableStateRegistry on the platform. 92 * 3) This objects can't be equals to any object which could be provided by a user as a custom key. 93 * 94 * Note: this function is a part of [LazyLayout] harness that allows for building custom lazy 95 * layouts. LazyLayout and all corresponding APIs are still under development and are subject to 96 * change. 97 */ getDefaultLazyLayoutKeynull98@Suppress("MissingNullability") expect fun getDefaultLazyLayoutKey(index: Int): Any 99