Search code examples
androidlayoutandroid-relativelayouthorizontalscrollview

Layout relative anchor in a RelativeLayout in a HorizontalScrollView doesn't work as intended


I have a HorizontalScrollView with a RelativeLayout containing three Views. One is centered in parent, and the other two should be placed relative the centered view as anchor. This doesn't give the intended results. But when the RelativeLayout is not placed inside the scroll view, it does.

<?xml version="1.0" encoding="utf-8"?>
<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="200dp">
    <RelativeLayout
        android:id="@+id/container"
        android:layout_width="600dp"
        android:layout_height="200dp"
        android:background="#eeeeee">
        <View
            android:id="@+id/center"
            android:layout_width="100dp"
            android:layout_height="match_parent"
            android:layout_centerInParent="true"
            android:background="#ff0000" />
        <View
            android:id="@+id/left"
            android:layout_width="50dp"
            android:layout_height="match_parent"
            android:layout_toLeftOf="@+id/center"
            android:background="#00ff00" />
        <View
            android:id="@+id/right"
            android:layout_width="50dp"
            android:layout_height="match_parent"
            android:layout_toRightOf="@+id/center"
            android:background="#0000ff" />
    </RelativeLayout>
</HorizontalScrollView>

The code above gives the following result:

HorizontalScrollView

The space on the left side has the same width as the red (centered) view, as of it was placed to the right if it before it was centered. The green view is placed outside (to the left) the container with the same reasoning. Why aren't the layout of the green and blue views updated correctly when the red view is centered?

However, if I just use the RelativeLayout without placing it in the scroll view it works as intended.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:background="#eeeeee">
    <View
        android:id="@+id/center"
        android:layout_width="100dp"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"
        android:background="#ff0000" />
    <View
        android:id="@+id/left"
        android:layout_width="50dp"
        android:layout_height="match_parent"
        android:layout_toLeftOf="@+id/center"
        android:background="#00ff00" />
    <View
        android:id="@+id/right"
        android:layout_width="50dp"
        android:layout_height="match_parent"
        android:layout_toRightOf="@+id/center"
        android:background="#0000ff" />
</RelativeLayout>

RelativeLayout

This side-by-side alignment is just to give a simple showcase. In practice, margins (both positive and negative) will be added to make a gap or overlap between the views, hence a LinearLayout would not do the trick.

The note at the Android documentation for RelativeLayout suggests that there is a known issue regarding this. Is there a workaround?


Solution

  • The RelativeLayout needs to be wrapped within a LinearLayout for the layout calculations to be forced to position the views in the right order.

    <?xml version="1.0" encoding="utf-8"?>
    <HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="200dp">
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <RelativeLayout
                android:id="@+id/container"
                android:layout_width="600dp"
                android:layout_height="200dp"
                android:background="#eeeeee">
                <View
                    android:id="@+id/center"
                    android:layout_width="100dp"
                    android:layout_height="match_parent"
                    android:layout_centerInParent="true"
                    android:background="#ff0000" />
                <View
                    android:id="@+id/left"
                    android:layout_width="50dp"
                    android:layout_height="match_parent"
                    android:layout_toLeftOf="@+id/center"
                    android:background="#00ff00" />
                <View
                    android:id="@+id/right"
                    android:layout_width="50dp"
                    android:layout_height="match_parent"
                    android:layout_toRightOf="@+id/center"
                    android:background="#0000ff" />
            </RelativeLayout>
        </LinearLayout>
    </HorizontalScrollView>