[ScrollView fillViewport] There were a few discuss...
# compose
c
[ScrollView fillViewport] There were a few discussions about how to replicate ScrollView-s fillViewport=true behaviour. The same can be definitely achieved with a Column having
fillMaxHeight
height, and then applying the
verticalScroll
modifier on it. But if we use an inner Column, then the way it is measured is different than what we got used to using XML layouts. Setting an inner Columns height to
wrapContentHeight
and applying
.weight(1f)
on it only respects the weight modifier, but the
wrapContentHeight
modifier is ignored. This makes the
Column
cut its children. Is there a workaround for this? Sample code in đź§µ
âž• 2
Here is my example setup in Compose
Column( Modifier .fillMaxSize() .verticalScroll(rememberScrollState()) .background(color = Color.Red) ) { Text(text = “Header”) Column( Modifier .wrapContentHeight() .weight(1f) .background(color = Color.Blue) ) { Spacer( modifier = Modifier .fillMaxWidth() .height(900.dp) ) } Text(text = “Footer”) }
This creates the following result. Notice the Footer being visible, despite adding a 900 dp tall child inside the inner Column.
The same layout created using XML
Copy code
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="<http://schemas.android.com/apk/res/android>"
    xmlns:tools="<http://schemas.android.com/tools>"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#ec0000"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Header" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="#0000ec">

            <View
                android:layout_width="match_parent"
                android:layout_height="900dp" />
        </LinearLayout>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Footer" />

    </LinearLayout>
</ScrollView>
This creates a scrollable screen, witch respects the 900 dp height of the inner content
a
I think you are misunderstanding
Modifier.wrapContentHeight()
. It is not the same as
wrap_content
in View system as it doesn't change layout size. It only controls how the content is aligned in the incoming constraints. See the doc:
If the content's measured size is smaller than the minimum height constraint, align it within that minimum height space. If the content's measured size is larger than the maximum height constraint (only possible when unbounded is true), align over the maximum height space.
To achieve what you want, you can add a spacer with `Modifier.weight(1f)`:
Copy code
Column(
    Modifier
        .fillMaxSize()
        .verticalScroll(rememberScrollState())
        .background(color = Color.Red)
) {
    Text(text = "Header")
    Column(
        Modifier.background(color = Color.Blue)
    ) {
        Spacer(
            modifier = Modifier
                .fillMaxWidth()
                .height(900.dp)
        )
    }
    Spacer(modifier = Modifier.weight(1f))
    Text(text = "Footer")
}
c
Yeah, I know that I can lift the Child applying weight to make it work, but this way I have to apply the Blue background on the Spacer. With blue background it is not a big deal, but if you have more complicated background decorations, like rounded corners, it gets more and more complicated
132 Views