Android Layouts Supporting Orientation

Dave Smith
Dave Smith

It's been my experience that most developers don't want to deal with screen rotation in their applications. They will either specifically code the app not to respond to rotation events (which can look weird when you have to slide the screen and use the keyboard), or they will forget that there are instances where the screen orientation rotates for you by default (and their portrait-centric layout goes nuts or gets cut off). This is one of those subtle details that can drag down the user experience in a big way if the developer is not careful.

If your platform of choice is Android, my only question if you're afraid of screen rotation would be...why? Android makes dealing with different orientations in your views very simple. If you've opted to define your layouts with XML (which you probably should anyway), then all that is required is a second XML file defining the second orientation (probably landscape), and some resource syntax to describe to Android how and when to choose the proper layout. Defining layouts in XML is so simple, adding another doesn't requre significant effort.

The general steps are as follows:

  1. Create two folders in the resource bundle (res folder in the project)— layout and layout-land:
    • layout will hold all the XML layouts for portrait mode
    • layout-land will hold all the XML layouts for landscape mode
  2. Create an XML layout in both folders with the SAME name (i.e. main.xml)
    • There will now be a res/layout/<name>.xml and a res/layout-land/<name>.xml
  3. Build each layout to match the proper screen orientation.
  4. POOF! You're done. Android will handle the rest at runtime.

So what's happening?  Well, -land is an alternate resource that Android recognizes for screen orientation. Creating the resource directory layout-land tells Android specifics about how the contents of the directory are to be used—specifically layouts for landscape.

Let's look at a quick example:

Let's say I have a layout with four image buttons. In portrait mode, I want those buttons to block in a 2x2 arrangement. However, in landscape mode, that block runs off the screen, so I want them all in a single row. I will define two layouts:

res/layout/main.xml

<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
  <TableRow>
    <ImageButton
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/image1"/>
    <ImageButton
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/image2"/>
  </TableRow>
  <TableRow>
    <ImageButton
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/image3"/>
    <ImageButton
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/image4"/>
  </TableRow>
</TableLayout>

res/layout-land/main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="horizontal">
  <ImageButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/image1"/>
  <ImageButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/image2"/>
  <ImageButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/image3"/>
  <ImageButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/image4"/>
</LinearLayout>

Whenever the main.xml view is inflated, it will display either the TableLayout version or the LinearLayout version, depending on the screen orientation.