Adapting To Display Orientation
×
Home Courses Community Support
Gray Matter

First Step Towards Android: Introduction »

Understanding Activities and Intents »

Hands On With UI Designing In Android (Controls-Views,Widgets and Layouts) »

Updating... »

Adapting To Display Orientation

One of the key features of modern smartphones is their ability to switch screen orientation, and Android is no exception. Android supports two screen orientations: portrait and landscape. By default, when you change the display orientation of your Android device, the current activity that is displayed will automatically redraw its content in the new orientation. This is because the onCreate() event of the activity is fi red whenever there is a change in display orientation.

enlightenedWhen you change the orientation of your Android device, your current activity is actually destroyed and then re-created.

However, when the views are redrawn, they may be drawn in their original locations (depending on the layout selected). Below figure shows one of the examples illustrated earlier displayed in both portrait and landscape mode. As you can observe in landscape mode, a lot of empty space on the right of the screen could be used. Furthermore, any additional views at the bottom of the screen would be hidden when the screen orientation is set to landscape.

In general, you can employ two techniques to handle changes in screen orientation:

  • Anchoring: The easiest way is to “anchor” your views to the four edges of the screen. When the screen orientation changes, the views can anchor neatly to the edges.
  • Resizing and repositioning: Whereas anchoring and centralizing are simple techniques to ensure that views can handle changes in screen orientation, the ultimate technique is resizing each and every view according to the current screen orientation.

Anchoring Views

Anchoring could be easily achieved by using RelativeLayout. Consider the following main.xml containing five Button views embedded within the <RelativeLayout> element:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Top Left Button"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
/>
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Top Right Button"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
/>
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Bottom Left Button"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
/>
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Bottom Right Button"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
/>
<Button
android:id="@+id/button5"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Middle Button"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
/>
</RelativeLayout>


Observe the following attributes found in the various Button views:

Attribute Description
layout_alignParentLeft Aligns the view to the left of the parent view
layout_alignParentRight Aligns the view to the right of the parent view
layout_alignParentTop Aligns the view to the top of the parent view
layout_alignParentBottom Aligns the view to the bottom of the parent view
layout_centerVertical Centers the view vertically within its parent view
layout_centerHorizontal Centers the view horizontally within its parent view


Below figure shows the activity when viewed in portrait mode.


 

When the screen orientation changes to landscape mode, the four buttons are aligned to the four edges of the screen, and the center button is centered in the middle of the screen with its width fully stretched (see below figure).

Resizing and Repositioning

Apart from anchoring your views to the four edges of the screen, an easier way to customize the UI based on screen orientation is to create a separate res/layout folder containing the XML files for the UI of each orientation. To support landscape mode, you can create a new folder in the res folder and name it as layout-land (representing landscape). Basically, the main.xml file contained within the layout folder defines the UI for the activity in portrait mode, whereas the main.xml file in the layout-land folder defines the UI in landscape mode. The following shows the content of main.xml under the layout folder:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Top Left Button"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
/>
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Top Right Button"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
/>
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Bottom Left Button"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
/>
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Bottom Right Button"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
/>
<Button
android:id="@+id/button5"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Middle Button"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
/>
</RelativeLayout>


The following shows the content of main.xml under the layout-land folder (there are some statements that are the additional views to display in landscape mode):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Top Left Button"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
/>
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Top Right Button"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
/>
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Bottom Left Button"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
/>
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Bottom Right Button"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
/>
<Button
android:id="@+id/button5"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Middle Button"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
/>
<Button
android:id="@+id/button6"
android:layout_width="180px"
android:layout_height="wrap_content"
android:text="Top Middle Button"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:layout_alignParentTop="true"
/>
<Button
android:id="@+id/button7"
android:layout_width="180px"
android:layout_height="wrap_content"
android:text="Bottom Middle Button"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
/>
</RelativeLayout>


When the activity is loaded in portrait mode, it will show five buttons, as shown in Figure.


When the activity is loaded in landscape mode, there are now seven buttons (see Figure), proving that different XML files are loaded when the device is in a different orientation.

Using this method, when the orientation of the device changes, Android will automatically load the appropriate XML file for your activity depending on the current screen orientation.

Managing changes to the screen orientation

Now that you have looked at how to implement the two techniques for adapting to screen orientation changes, let’s explore what happens to an activity’s state when the device changes orientation. To understand this in a better manner let's take an example which shows the behavior of an activity when the device changes orientation.

follow these steps :-

step1: Create a new Android project and name it Orientations.

step2: Now we will modify activity_main.xml file. So add the following code into activity_main.xml file-

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >
    
    <EditText
	android:id="@+id/txtField1"
	android:layout_width="fill_parent"
	android:layout_height="wrap_content" />
	<EditText
	android:layout_width="fill_parent"
	android:layout_height="wrap_content" />

</LinearLayout>


step3: Now we will modify MainActivity.java file. So add the following code into MainActivity.java file-

package com.example.orientations;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.util.Log;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d("StateInfo", "onCreate");
    }
    @Override
    public void onStart() {
    Log.d("StateInfo", "onStart");
    super.onStart();
    }
    @Override
    public void onResume() {
    Log.d("StateInfo", "onResume");
    super.onResume();
    }
    @Override
    public void onPause() {
    Log.d("StateInfo", "onPause");
    super.onPause();
    }
    @Override
    public void onStop() {
    Log.d("StateInfo", "onStop");
    super.onStop();
    }
    @Override
    public void onDestroy() {
    Log.d("StateInfo", "onDestroy");
    super.onDestroy();
    }
    @Override
    public void onRestart() {
    Log.d("StateInfo", "onRestart");
    super.onRestart();
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
    
}


step4: Now Press F11 key to debug the application on the Android Emulator or on the device. Let's see the output window now.

Enter some text into the two EditText views.

Change the orientation of the Android Emulator by pressing Ctrl+F11. Figure shows the emulator in landscape mode. Note that the text in the first EditText view is still visible, while the second EditText view is now empty.


Observe the output in the LogCat window (you need to switch to the Debug perspective in Eclipse). You should see something like this:



Persisting State Information during Changes in Configuration

So far, you have learned that changing screen orientation destroys an activity and re-creates it. Keep in mind that when an activity is re-created, the current state of the activity may be lost. When an activity is killed, it will fire one or more of the following two events:

onPause() — This event is always fired whenever an activity is killed or pushed into the background.

onSaveInstanceState() — This event is also fired whenever an activity is about to be killed or put into the background (just like the onPause() event). However, unlike the onPause() event, the onSaveInstanceState event is not fired when an activity is being unloaded from the stack (for example, when the user pressed the Back button), because there is no need to restore its state later.

In short, to preserve the state of an activity, you could always implement the onPause() event, and then use your own ways to preserve the state of your activity, such as using a database, internal or external file storage, etc.
If you simply want to preserve the state of an activity so that it can be restored later when the activity is re-created (such as when the device changes orientation), a much simpler way would be to implement the onSaveInstanceState() method, as it provides a Bundle object as an argument so that you can use it to save your activity’s state. The following code shows that you can save the string ID into the Bundle object during the onSaveInstanceState event:

@Override
public void onSaveInstanceState(Bundle outState) {
//---save whatever you need to persist---
outState.putString("ID", "1234567890");
super.onSaveInstanceState(outState);
}


When an activity is re-created, the onCreate() event is first fired, followed by the onRestoreInstanceState() event, which enables you to retrieve the state that you saved previously in the onSaveInstanceState event through the Bundle object in its argument:

@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
//---retrieve the information persisted earlier---
String ID = savedInstanceState.getString("ID");
}


Although you can use the onSaveInstanceState() event to save state information, note the limitation that you can only save your state information into a Bundle object. If you need to save more complex data structures, then this is not an adequate solution. Another event handler that you can use is the onRetainNonConfigurationInstance() event. This
event is fired when an activity is about to be destroyed due to a confi guration change. You can save your current data by returning it in this event, like this:

@Override
public Object onRetainNonConfigurationInstance() {
//---save whatever you want here; it takes in an Object type---
return("Some text to preserve");
}

 

enlightenedWhen screen orientation changes, this change is part of what is known as a configuration change. A confi guration change will cause your current activity to be destroyed.


Note that this event returns an Object type, which pretty much allows you to return any data type. To extract the saved data, you can extract it in the onCreate() event, using the
getLastNonConfigurationInstance() method, like this:

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d("StateInfo", "onCreate");
String str = (String) getLastNonConfigurationInstance();
}

 

Detecting orientation changes

Sometimes you need to know the device’s current orientation during run time. To determine that, you can use the WindowManager class. The following code snippet demonstrates how you can programmatically detect the current orientation of your activity:

import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
//...
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//---get the current display info---
WindowManager wm = getWindowManager();
Display d = wm.getDefaultDisplay();
if (d.getWidth() > d.getHeight())
{
//---landscape mode---
Log.d("Orientation", "Landscape mode");
}
else
{
//---portrait mode---
Log.d("Orientation", "Portrait mode");
}
}

The getDefaultDisplay() method returns a Display object representing the screen of the device. You can then get its width and height and deduce the current orientation.


Controlling the Orientation of the Activity

Occasionally you might want to ensure that your application is only displayed in a certain orientation. For example, you may be writing a game that should only be viewed in landscape mode. In this case, you can programmatically force a change in orientation using the setRequestOrientation() method of the Activity class:

import android.content.pm.ActivityInfo;
public class MainActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//---change to landscape mode---
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}


To change to portrait mode, use the ActivityInfo.SCREEN_ORIENTATION_PORTRAIT constant:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);


Besides using the setRequestOrientation() method, you can also use the android:screenOrientation attribute on the <activity> element in AndroidManifest.xml as follows to constrain the activity to a certain orientation:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.Orientations"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".MainActivity"
android:label="@string/app_name"
android:screenOrientation="landscape" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="9" />
</manifest>

The preceding example constrains the activity to a certain orientation (landscape in this case) and prevents the activity from being destroyed; that is, the activity will not be destroyed and the onCreate() event will not be fired again when the orientation of the device changes. Following are two other values that you can specify in the android:screenOrientation attribute:
portrait Portrait mode
sensor Based on the accelerometer

 

← Preview

Customization In Layouts

Next →

Creating UI Of An Application Via Code

NOTES

Our mission is to provide highly effective and quality education via innovative solutions. Geeksdemy look forward to bridge the gap between in-demand technology and academics in order to deliver innovative, easy, interesting and affordable learning across the Globe.

Courses

  • Python
  • Game Development with Unity 3D
  • Arduino
  • PCB & Circuit Designing
  • Robotics and Embedded C
  • 8051/8052 Embedded Systems
  • QuadCopter & UAV
  • MATLAB with Robotics
  • Raspberry Pi
Learn On the Go!
Get the Android App
Get the iOS App