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

dbaelz

04/12/2022, 10:18 AM
I've tried to build an EPG as a Grid and struggle to get a working, lazy-loading solution. My use case: • The EPG consists of 120+ rows (tv stations) and every row consist of 200+ row items (tv programs of the different broadcast times). • Every item in the row has a different width based on its broadcasting time. On the x-axis only a specific timespan is displayed and the user can scroll throw them horizontal. Because the x-axis represents the time, a horizontal scroll should change all items in all rows. • It should be possible to scroll throw both horizontal (tv programs based on time) and vertical (different tv stations) on the same time. With non-lazy Composable it works, but with the mentioned amount of items the performance is really bad. Obviously, it should be done lazy. Unfortunately, I didn't find a solution that worked for me. Especially syncing the scroll state of the different rows was a problem. I looked into different approaches to do it with LazyList Composables or Lazy Grid (e.g. syncing the scroll with NestedScrollConnection and shared state). See some examples in the thread. Afaik there isn't a Composable that supports horizontal and vertical lazy loading for such a use case out of the box. Has someone has an idea how to tackle that it without writing all of it by myself or an easy way to do it with a Custom Layout?
What I did so far: • LazyColumn with Row / Column with LazyRow -> Stuttering. Obviously, need lazy loading • LazyColumn + LazyRow (without NestedScrollConnection): Not possible, due nested scrollable Composable • LazyColumn + LazyRow with NestedScrollConnection: All attempts to sync the horizontal scrolling of the LazyRows failed. Tried to sync with with shared lazyliststate, but it doesn't work reliable • Experimental LazyVerticalGrid and LazyVerticalGrid -> Also can't be nested. With NestedScrollConnection I had strange rendering behavior
n

nitrog42

04/12/2022, 12:03 PM
I think it would be interesting if you could provide a "mock" sample of the "LazyColumn + LazyRow with NestedScrollConnection" use case it might just need some tuning the only way I see is to make your own Lazy component but... it's probably hard. you can also check of the Compose DataTable https://proandroiddev.com/jetpack-compose-data-tables-33a247f59fd5 it's not available anymore (and it will not be soon it seems) but on an old compose version you should be able to look at the code
d

dbaelz

04/12/2022, 2:35 PM
I've stumbled over that post before. Good idea to look up the old implementation and try to replicate it or make a similar one. Not sure if it provides everything required, but it might be a good starting point. An update: It seems to work with a simplified example. I had some problems with our more complex UI, but with this newly created simplified example it works way better. It still has a minor scrolling glitches that very seldom happens on very fast scrolling (on debug build). Any recommendations if this is a good/correct way to do it? It should be possible to tweak/performance improve our complex ui way more if the general approach is fine.
Copy code
@Composable
fun LazyColumnAndLazyRowExample(items: List<Station> = createDummyData()) {
    var offset by remember { mutableStateOf(0f) }
    val lazyListState = rememberLazyListState()

    LaunchedEffect(offset) {
        lazyListState.dispatchRawDelta(-offset)
    }

    val nestedScrollConnection = remember {
        object : NestedScrollConnection {
            override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
                Timber.d("NestedScrollConnection onPreScroll ${available.x}")
                offset = available.x
                return available
            }
        }
    }

    LazyColumn {
        items(items) { item ->
            LazyRow(modifier = Modifier.nestedScroll(nestedScrollConnection), state = lazyListState) {
                items(item.programs) { program ->
                    Text(
                        text = program.text,
                        modifier = Modifier
                            .padding(4.dp)
                            .border(2.dp, Color.Blue)
                            .padding(4.dp)
                    )
                }
            }
        }
    }
}

data class Station(val programs: List<Program>)
data class Program(val text: String)
179 Views