https://kotlinlang.org logo
#compose
Title
# compose
t

Timo Drick

05/14/2020, 9:22 AM
Because the AdapterList is not working correctly for now. I implemented my own custom list. I think the performance is more or less similar but it do not crash so often and it calls onDispose when a item is not visible any more. And also for me it is impressive that it is possible to implement a AdapterList in 60 lines of code.
😮 2
Copy code
private const val threshold = 200f

@Composable
fun <T: Any>VerticalList(modifier: Modifier = Modifier, data: List<T>, itemCallback: @Composable() (T) -> Unit) {
    val scrollerPosition = ScrollerPosition()
    var firstVisibleItem by stateFor(data) { 0 }
    var lastVisibleItem by stateFor(data) { 0 }
    var height by stateFor(data) { 0f }
    var childrenHeight by stateFor(data) { 0f }
    val itemHeightArray = remember(data) { FloatArray(data.size) { 0f } }

    VerticalScroller(
        modifier = modifier.onPositioned {
            height = it.size.height.value.toFloat()
        },
        scrollerPosition = scrollerPosition) {
        if (data.isNotEmpty()) {
            Column(Modifier.onPositioned {
                childrenHeight = it.size.height.value.toFloat()
                val scroll = scrollerPosition.value
                val firstHeight = itemHeightArray[firstVisibleItem]
                val lastHeight = itemHeightArray[lastVisibleItem]
                // check if we must decrease the first visible item
                if (scroll <= threshold && firstVisibleItem > 0) { // add item in front of the list
                    firstVisibleItem--
                    scrollerPosition.scrollBy(itemHeightArray[firstVisibleItem]) // scroll height of added item
                }
                // check if we can increase the first visible item
                if (scroll > firstHeight + lastHeight + threshold) { // remove invisible item
                    firstVisibleItem++
                    scrollerPosition.scrollBy(-firstHeight) // scroll height of removed item
                }
                // check if we must increase last visible item
                val pixelsInvisible = childrenHeight - height - scroll // invisible pixels left
                if (pixelsInvisible <= threshold && lastVisibleItem < data.size - 1) {
                    lastVisibleItem++
                }
                // check if we can decrease the last visible item
                if (pixelsInvisible > lastHeight + firstHeight + threshold && lastVisibleItem > 0) {
                    lastVisibleItem--
                }
            }) {
                for (i in firstVisibleItem..lastVisibleItem) {
                    VerticalListItem(item = data[i], onPositioned = { height ->
                        itemHeightArray[i] = height.toFloat() // remember height
                    }, itemCallback = itemCallback)
                }
            }
        }
    }
}

@Composable
fun <T: Any>VerticalListItem(@Pivotal item: T, onPositioned: (Int) -> Unit, itemCallback: @Composable() (T) -> Unit) {
    Box(modifier = Modifier.onPositioned { onPositioned(it.size.height.value) }, children = { itemCallback(item) })
}