How to focus on a specific item in a row based on some flag?

172 Views Asked by At

Consider the following code :

val tvListState = rememberTvLazyListState()
val coScope = rememberCoroutineScope()
Column{
    TvLazyRow(
        horizontalArrangement = Arrangement.spacedBy(15.dp),
        state = tvListState,
        modifier = modifier
        .padding(end = 5.dp)
        , pivotOffsets = PivotOffsets(0f)) { *items* }
    TvLazyRow(
        horizontalArrangement = Arrangement.spacedBy(15.dp),
        state = tvListState,
        modifier = modifier
        .padding(end = 5.dp)
        , pivotOffsets = PivotOffsets(0f)) { *items* }
    TvLazyRow(
        horizontalArrangement = Arrangement.spacedBy(15.dp),
        state = tvListState,
        modifier = modifier
        .padding(end = 5.dp)
        , pivotOffsets = PivotOffsets(0f)) { *items* }
}

What I want to do is to focus on a specific item in one of the lazy rows when we enter the row, and have it tied to a flag, could be something like preFocusOnItem. In my current implementation I am having to call focus on this item using itemsRequester[preFocusOnItem].requestfocus() inside LaunchedEffect, where the array is used to assign a focus requester to each of the items. The problem with this approach is the focus first comes to the item that scrolling naturally will bring focus to, and after a split second the focus jumps to the item I want to focus on.

How do I directly call focus on the preFocusOnItem item when entering one of the TvLazyRows??

2

There are 2 best solutions below

4
vighnesh153 On BEST ANSWER

You can make use of focusProperties on the TvLazyRow to intercept the focus and implement the enter function in it to match with some condition and return respective focus requesters.

In the following example, I am focussing on:

  • index 2 in first row
  • index 3 in second row
  • index 1 in 3rd row

val rows = 3
val columns = 4

val focusRequesters = remember {
    (1..(rows * columns)).map { FocusRequester() }
}

Surface(Modifier.fillMaxSize()) {
    TvLazyColumn {
        items(rows) { row ->
            TvLazyRow(
                modifier = Modifier.focusProperties {
                    enter = {
                        when (row) {
                            0 -> focusRequesters[row * columns + 2]
                            1 -> focusRequesters[row * columns + 3]
                            2 -> focusRequesters[row * columns + 1]
                            else -> FocusRequester.Default
                        }
                    }
                }
            ) {
                items(columns) { column ->
                    val index = row * columns + column

                    AppCard(column, Modifier.focusRequester(focusRequesters[index]))
                }
            }
        }
    }
}

@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun AppCard(index: Int, modifier: Modifier = Modifier) {
    Surface(
        onClick = {},
        modifier = modifier.width(200.dp).aspectRatio(16f / 9)
    ) {
        Text(text = "Card=$index")
    }
}

0
BenjyTec On

You can set an initial scroll position to a LazyColumn or LazyRow by using the default rememberLazyListState like this:

// this will initialize scrolling position to the 5th item in the LazyList
val listState = rememberLazyListState(initialFirstVisibleItemIndex = 5)

LazyRow(
    state = listState
) {
    // ...
}