I've tried to build an EPG as a Grid and struggle ...
# compose
d
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
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
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)
p
@dbaelz, could you kindly share your wisdom on this old post? It would be a boon to a fellow developer in distress. 😅 I’m knee-deep in the quest of crafting an EPG guide with Compose for Android TV. My journey has led me to similar epiphanies as yours. The goal? A sleek, seamless scroll through timelines and channels, encompassing over 100 channels and 20 days of focusable programs. I’m currently weaving together an implementation inspired by https://github.com/oleksandrbalan/programguide, with some personal twists and a sprinkle of lazy-loading magic via paging. Though I’ve conjured something functional, it’s still far from perfect – the overall performance, scroll animations, focus behavior, and fast scrolling are all in need of serious TLC. Before I rally the troops for a UX lamentation session, I stumbled upon your post, hoping it holds the key to my deliverance. Your insights could be the lighthouse guiding me away from the rocks of frustration.
232 Views