Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jetpack Compose - Scroll to focused composable in Column

I have UI like this:

val scrollState = rememberScrollState()
        Column(
            modifier = Modifier
                .fillMaxSize(1F)
                .padding(horizontal = 16.dp)
                .verticalScroll(scrollState)
        ) {

            TextField(...)
 // multiple textfields
             TextField(
                        //...
                        modifier = Modifier.focusOrder(countryFocus).onFocusChanged {
                            if(it == FocusState.Active) {
                               // scroll to this textfield
                            }
                        },
                    )
         }

I have multiple TextFields in this column and when one of them is focused I want to scroll Column to it. There is a method in scrollState scrollState.smoothScrollTo(0f) but I have no idea how to get a focused TextField position.

Update:

It seems that I've found a working solution. I've used onGloballyPositioned and it works. But I'm not sure if it the best way of solving this.

var scrollToPosition = 0.0F

TextField(
   modifier = Modifier
    .focusOrder(countryFocus)
    .onGloballyPositioned { coordinates ->
        scrollToPosition = scrollState.value + coordinates.positionInRoot().y
    }
    .onFocusChanged {
    if (it == FocusState.Active) {
        scope.launch {
            scrollState.smoothScrollTo(scrollToPosition)
        }
    }
}
)
like image 990
radzio Avatar asked Feb 17 '21 20:02

radzio


2 Answers

It seems that using LazyColumn and LazyListState.animateScrollToItem() instead of Column could be a good option for your case.

Reference: https://developer.android.com/jetpack/compose/lists#control-scroll-position

By the way, thank you for the information about onGloballyPositioned() modifier. I was finding a solution for normal Column case. It saved me a lot of time!

like image 142
mechurak Avatar answered Sep 20 '22 12:09

mechurak


There is a new thing in compose called RelocationRequester. That solved the problem for me. I have something like this inside of my custom TextField.

val focused = source.collectIsFocusedAsState()
val relocationRequester = remember { RelocationRequester() }
val ime = LocalWindowInsets.current.ime
if (ime.isVisible && focused.value) {
    relocationRequester.bringIntoView()
}
like image 29
Jeremiah Stephenson Avatar answered Sep 16 '22 12:09

Jeremiah Stephenson