I have a 3 Column. In 1st Column of components are...
# compose
k
I have a 3 Column. In 1st Column of components are 2nd and 3rd Column. In 2nd Column there are so many components inside that. In last 3rd Column I have a few items and I am sticking at the bottom of screen. I have done without any problem . In smaller screen item is going behind, so my supervisor mention that all item will automatically scroll of 2nd Column which is clearly above of 3rd Column.
Copy code
@Composable
fun Xyz(){
    Theme {
        val scrollState = rememberScrollState()

        LaunchedEffect(
            keyOneIsTrue,
            keyTwoIsTrue
        ) {
            val newValue = scrollState.maxValue
            scrollState.animateScrollTo(newValue)
        }
        Column(
            modifier = Modifier
                .padding(dimensionResource(R.dimen.margin_screen_edge_sides))
                .fillMaxSize()
                .verticalScroll(rememberScrollState()),
//            verticalArrangement = <http://Arrangement.Top|Arrangement.Top>
            or
//                verticalArrangement = Arrangement.Arrangement.SpaceBetween
        ) {
            Column(
                modifier = Modifier
                    .verticalScroll(scrollState)
                    .weight(1f),
                horizontalAlignment = Alignment.CenterHorizontally,
            ) {
                // so many item in here.
                //  If here items is behind of 3rd column then automatically scroll the item when user land of this this screen
            }
            Column {
                Button()
                // may be more item in here
            }
        }
    }
}
Actual Output
Expected Output Scenario 1
Note:- Item will be increase in 2nd Column i.e. I added logic in AnimatedVisibility so when recompose it will added the item.
k
What's the question?
k
@Kirill Grouchnikov how to auto scroll item in column
m
@KotlinLeaner If you’re asking how to programatically scroll to a specific item on the screen, that’s semi-complicated with a regular Column. Generally, you would save off the scrollState:
Copy code
val scrollState = rememberScrollState()
and pass that to the
verticalScroll
modifier function you have above. Once you do that, you can ask the scrollState to scroll to a specific pixel offset within the measured size of the column. So, if the entire column is measured 1500 at pixel tall, you can ask it to scroll to any particular location:
Copy code
val scope = rememberCoroutineScope()

...
scope.launch {
    scrollState.animateScrollTo(1000)
}
The problem with this, of course is that it’s entirely pixel based, not based on any child index or anything like that. If you want to scroll to specific items, i think that LazyColumn might be a better choice for you, as
LazyListState
(the equivalent of ScrollState) has an
animateScrollToItem
function where you can give it the index of the item.
k
So how can I measure the column pixel ?
k
Hi @Jonas, I tried some piece of code but nothing works. Can you please guide me what I am doing wrong in here?
Copy code
@Preview(showBackground = true, widthDp = 250, heightDp = 320)
@Composable
fun Xyz() {
    Theme {
        var itemClicked by remember { mutableStateOf(0) }
        val favourites = remember { mutableStateListOf<String>() }
        val scrollState = rememberScrollState()
        var columnHeightPx by remember { mutableStateOf(0) }
        LaunchedEffect(favourites.size > 0) {
            scrollState.animateScrollTo(columnHeightPx)
        }
        Column(
            modifier = Modifier
                .padding(dimensionResource(R.dimen.margin_screen_edge_sides))
                .fillMaxSize()
                .verticalScroll(rememberScrollState()),
        ) {
            Column(
                modifier = Modifier
                    .onGloballyPositioned { coordinates ->
                        // Set column height using the LayoutCoordinates
                        columnHeightPx = coordinates.size.height
                    }
                    .verticalScroll(scrollState)
                    .weight(1f),
                horizontalAlignment = Alignment.CenterHorizontally,
            ) {
                favourites.forEach { text ->
                    Text(
                        text = "$text -> ${columnHeightPx}",
                        fontSize = 20.sp,
                        color = Red
                    )
                }
            }
            Column {
                Button(onClick = {
                    itemClicked++
                    favourites.add("item clicked $itemClicked")
                }) {
                    Text(text = "Add me")
                }
            }
        }
    }
}
j
Two things I can spot in a hurry: • nested vertical scroll containers - seems wrong and does not work I guess. • as you get the height after the first render it also needs to be a key in your launched effect, otherwise it does not fire again when you get the correct value
k
So how can I fixed the nested scroll ?
j
Sry, I have no time atm to help you.
k
Ok don't help me now😢, but when you have free time then please guide me on this 🥲
j
Earliest in two days, hope you can find someone else in the meantime or fix the issue yourself.
k
I'll try my best to solve this problem. If I solved the problem, then I'll send the message in here, otherwise someone guide me on this thread. Thanks for your time.
k
You need to switch from nested columns to a single scrollable container, ideally LazyColumn
k
The above example which I was mentioned is very basic to learn something . In my real project
2nd column
inside there are so many items i.e. like
Row
,
Text
,
Image
. So how can I switch all this stuff in
LazyColumn
?
k
Is there anything unclear in the LazyColumn documentation?
k
No, I have basic knowledge of
LazyColumn
.
Are you saying to change all 2nd column item`Row`,
Text
,
Image
.. etc to
LazyColumn
?
k
Everything as a single lazy column. Don’t try to nest containers that are scrollable along the same direction
m
The problem in the latest piece of code is that you have a Column inside a Column, both with a "verticalScroll" modifier. You should only put the "verticalScroll" modifier on the outermost column. Secondly, that outermost column is creating a new scrollState, and you should instead be passing it the one you created and saved to a variable.
k
@Kirill Grouchnikov I totally understand your suggestion and really appreciate it. But my problem is I want to make a
button
at bottom of screen which is unscrollable and other item which is above will be scrollable. I found out on this example and similar to this example
m
As for LazyColumn, it's not difficult:
Copy code
val state = rememberLazyListState()
    LazyColumn(state=state) {
        item {
            ...
        }
        item {
            ...
        }
    }
And when you want to scroll:
Copy code
scope.launch {
    state.animateScrollToItem(index)
}
Ah. the sticky button.
k
yes that's the main problem.
m
Copy code
Column(modifier=Modifier.fillMaxSize()) {
   Column(
     modifier = Modifier
         .verticalScroll(scrollState)
         .weight(1.0f, true)
   ) {
       // put your scrollable content here
   }

   Column {
       // put your buttons in here.
   }
}
The "weight" modifier on the inner column tells it to take up all the remaining available space in it's parent container after the other elements are rendered. So in this case you then make that same column vertically scrollable. This gives you the container layout you are asking for.
This is pretty much no different than what you'd do in the view world with LinearLayout
k
One question, in
weight
modifier what is the use of 2nd parameter
true
means?
m
the "true" means to fill the available space.
Copy code
weight: Float	
The proportional width to give to this element, as related to the total of all weighted siblings. Must be positive.

fill: Boolean = true	
When true, the element will occupy the whole width allocated.