Friday, November 26, 2010

Flexible layout with RelativeLayout in Android

I often create a layout for my Android applications with a list and horizontal row of buttons on the bottom. Considering that Android devices come in very different sizes, you want to make this layout flexible so that the list takes up the entire area above the row of buttons on the bottom.

You could do this with a LinearLayout and use layout_weight. This often does not behave the way I want to because the LinearLayout is quite limited. I found an easier way to use a RelativeLayout, see the example: 
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      android:orientation="vertical">
    
     <LinearLayout android:id="@+id/button_bar"
          android:orientation="horizontal"
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:layout_alignParentBottom="true"
          >

        <Button android:id="@+id/add_task_context_button"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:layout_weight="1"
             android:text="@string/task_context_add_button_title"
             />
        <Button android:id="@+id/cancel_button"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:layout_weight="1"
             android:text="@string/cancel_button_title"
             />
        <Button android:id="@+id/ok_button"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:layout_weight="1"
             android:text="@string/ok_button_title"
             />
     </LinearLayout>

    <ListView android:id="@+id/android:list"
              android:layout_width="fill_parent" 
              android:layout_height="fill_parent"
              android:layout_alignParentTop="true"
              android:layout_above="@id/button_bar"
              android:drawSelectorOnTop="false"
              style="@style/list"  
              />

    <TextView android:id="@+id/android:empty"
              android:layout_width="fill_parent"
              android:layout_height="wrap_content"
              android:layout_alignParentTop="true"
              android:text="@string/no_task_contexts"
              style="@style/label"                
              android:padding="10px"
              />
              

</RelativeLayout>

When you use a RelativeLayout, pay attention to the order of components. Because you specify where components are positioned relative to the parent's borders and other components.

To make my layout work, I first specify the horizontal row of buttons first (button_bar), contained in a LinearLayout with android:layout_alignParentBottom="true". When you position the list on the top with android:layout_alignParentTop="true", you also attach the bottom of the list with the top of the button row with android:layout_above="@id/button_bar". This way, the RelativeLayout will stretch the list between the top of the parent and the top of the button_bar.