8

I have an activity in my app where I would like the user to be able to vertically scroll the content contained inside a LinearLayout which in turn is inside a ScrollView. Here is a summary of what the layout XML for this activity looks like:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ScrollView
        android:layout_width="fill_parent"
        android:layout_height="match_parent">
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_margin="20dip"
            android:orientation="vertical">

            <!-- a bunch of standard widgets, omitted for brevity -->

            <!-- everything renders but starting in this TextView -->
            <!-- content begins to get truncated -->
            <TextView
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:paddingLeft="20dp"
                android:gravity="left"
                android:textSize="20dip"/>

            <!-- this View, really just a trick for a horizontal row, is -->
            <!-- completely cutoff -->
            <View
                android:layout_width="fill_parent"
                android:layout_height="2dip"
                android:layout_marginTop="10dp"
                android:layout_marginBottom="10dp"
                android:background="@color/green" />
        </LinearLayout>
    </ScrollView>
</LinearLayout>

What I am observing is that content in the inner LinearLayout is being cutoff inside the ScrollView. In the final TextView above, when it contains little text, then the View below it does render in portrait, but does not in landscape. When this TextView contains a lot of text, then it gets cutoff in portrait mode.

I tried the recommendations I found on Stack Overflow. Adding bottom padding to the ScrollView did not resolve the problem, nor did swapping the ScrollView for a NestedScrollView.

Any helpful suggestions would be welcome. This is actually turning out to be a blocker.

Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360

2 Answers2

29

Change your inner LinearLayout's margin to padding. Or, if you really need it to be margin (maybe you're using a custom background), wrap your LinearLayout in a FrameLayout.

The ScrollView is taking its height (or, more accurately, it is computing its scrollable range) from the LinearLayout. This value doesn't include margins, so your ScrollView is going to be "too short" by the sum of the LinearLayout's top and bottom margins.

Ben P.
  • 52,661
  • 6
  • 95
  • 123
  • 4
    In other words, the `ScrollView` is assigned a height which is too short, and then when it comes time for it to actually view its `LinearLayout`, it stops short and truncates the sum of the top and bottom margins, which in my case was 40dp. – Tim Biegeleisen Jul 25 '17 at 15:01
  • I believe it's as simple as the CSS box model; padding is part of a view's dimensions and margin is not. Check out `ScrollView.canScroll()`... it compares the `ScrollView`'s height to the first child's height. – Ben P. Jul 25 '17 at 15:01
  • Thanks for the help, you made my day. I'm surprised I could find nothing on this on SO...maybe I was searching for the wrong thing. Hopefully your answer can help another weary Android developer :-) – Tim Biegeleisen Jul 25 '17 at 15:02
0

The margins are ignored while measuring, See this

So you can provide padding to your ScrollView and remove margins from your LinearLayout

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">

<ScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="20dp">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <!-- a bunch of standard widgets, omitted for brevity -->

        <!-- everything renders but starting in this TextView -->
        <!-- content begins to get truncated -->
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingLeft="20dp"
            android:gravity="left"
            android:textSize="20dip"/>

        <!-- this View, really just a trick for a horizontal row, is -->
        <!-- completely cutoff -->
        <View
            android:layout_width="match_parent"
            android:layout_height="2dip"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:background="@color/green" />
    </LinearLayout>
</ScrollView>

Also fill_parent is deprecated and renamed match_parent in API Level 8 and higher

Ayush Khare
  • 1,802
  • 1
  • 15
  • 26
  • 3
    Using padding on the scrollview will have some consequences that aren't necessarily desriable. The first is that the content will be clipped by the padding (though you can fix this with `android:clipToPadding="false"`). The other (which I don't know how to fix) is that the scrollbar will be inside the padding. – Ben P. Jul 25 '17 at 14:58
  • Yes I agree, the scrollbars will be inside padding. Thanks for pointing this out – Ayush Khare Jul 25 '17 at 15:00