TangSir
TangSir

Reputation: 197

How to focus a invisible item in lazyColumn on jetpackCompose

I want to scroll the lazyColumn when its child get focused.

I use rememberLazyListState's scrollToItem method to scroll the lazyColumn.

enter image description here

but when a item at top been scrolled out, it can't be focused again.

enter image description here

enter image description here

My sample code:


@Composable
fun ScrollableList(modifier: Modifier = Modifier) {
    val scrollState = rememberLazyListState()
    val scope = rememberCoroutineScope()
    LazyColumn(
        state = scrollState,
        modifier = Modifier.padding(5.dp),
        verticalArrangement = Arrangement.spacedBy(5.dp)
    ) {

        itemsIndexed(items = (0..10).toList()) { index, item ->
            FocusableBox(
                title = "ScrollBox-$index",
                onFocused = { focused ->
                    scope.launch {
                        if (focused) {
                            scrollState.scrollToItem(index)
                        }
                    }
                })
        }
    }
}

@Composable
fun FocusableBox(
    title: String,
    onFocused: (Boolean) -> Unit = {},
    requester: FocusRequester = FocusRequester(),
    modifier: Modifier = Modifier
) {
    var boxColor by remember { mutableStateOf(Color.White) }
    var focused by remember { mutableStateOf(false) }
    Box(
        Modifier
            .focusRequester(requester)
            .onFocusChanged {
                boxColor = if (it.isFocused) Color.Green else Color.Gray
                focused = it.isFocused
                onFocused(it.isFocused)
            }
            .focusable()
            .background(boxColor)
            .zIndex(if (focused) 1f else 0f)
    ) {
        Text(
            text = title,
            modifier = Modifier.padding(30.dp),
            color = Color.White,
            style = MaterialTheme.typography.subtitle2
        )
    }
}

Upvotes: 3

Views: 2873

Answers (1)

TangSir
TangSir

Reputation: 197

add

val scrollState = rememberLazyListState()

then after child been focused, use scrollState.layoutInfo.visibleItemsInfo to determine scroll up or scroll down.

@Composable
fun ScrollableList(modifier: Modifier = Modifier) {
    val scrollState = rememberLazyListState()
    val scope = rememberCoroutineScope()
    LazyColumn(
        state = scrollState,
        modifier = Modifier.padding(5.dp),
        verticalArrangement = Arrangement.spacedBy(5.dp)
    ) {

        itemsIndexed(items = (0..10).toList()) { index, item ->
            FocusableBox(
                title = "ScrollBox-$index",
                onFocused = { focused ->
                    scope.launch {
                        if (focused) {
                            val visibleItemsInfo = scrollState.layoutInfo.visibleItemsInfo
                            val visibleSet = visibleItemsInfo.map { it.index }.toSet()
                            if (index == visibleItemsInfo.last().index) {
                                scrollState.scrollToItem(index)
                            } else if (visibleSet.contains(index) && index != 0) {
                                scrollState.scrollToItem(index - 1)
                            }
                        }
                    }
                })
        }
    }
}

Upvotes: 2

Related Questions