Android Portrait and Landscape Screen Layout Example
When developing an Android app the Activity
screens that form the user interface can be viewed in both portrait and landscape modes. Since Android devices (phones and tablets) can be used in either orientation screen support for both is helpful to the user. Do this by building layouts for each mode, alternatively design the portrait layout and then wrap it in a ScrollView
.
(This tutorial assumes that an app can be created and run in Android Studio. If not familiar with app programming in Studio then Tek Eye has beginners articles.)
Here is a screen from a simple app. The app converts a loan's annual interest rate to the monthly rate and vice versa. The screen is on a 480 by 800 high dots per inch (HDPI) screen. The widget text size has been set to 18sp (scaled pixels).
When the device is rotated (Ctrl-Left Arrow on the emulator) the last TextView on the screen is no longer visible and is not accessible.
The Demo App Code
Before looking at addressing this problem here is the code. The screen was built in Studio using the Design tab for the opened Activity layout file (in this case activity_main.xml in the res/layout folder). Here is the XML layout code:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin" >
<TextView
android:text="Convert Interest Rates"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textTitle"
android:textSize="20sp"
android:textStyle="normal|bold"
android:layout_centerHorizontal="true" />
<TextView
android:text="Rate to Convert %"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView"
android:textSize="18sp"
android:layout_alignBaseline="@+id/editRate"
android:layout_alignBottom="@+id/editRate"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<RadioGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/radioGroup"
android:layout_below="@+id/editRate" >
<RadioButton
android:text="Yearly to Monthly"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/radioMonthly"
android:textSize="18sp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:checked="true"
android:layout_weight="1" />
<RadioButton
android:text="Monthly to Yearly"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/radioYearly"
android:textSize="18sp"
android:layout_below="@+id/radioMonthly"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginTop="14dp"
android:layout_weight="1" />
</RadioGroup>
<Button
android:text="Convert"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button"
android:layout_below="@+id/radioGroup"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginTop="16dp"
android:onClick="HandleClick" />
<TextView
android:text="Press Convert for % Result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textResult"
android:textSize="18sp"
android:layout_below="@+id/button"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginTop="21dp"
android:layout_weight="1" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="numberDecimal"
android:id="@+id/editRate"
android:width="100dp"
android:text="0.0"
android:layout_below="@+id/textTitle"
android:layout_toRightOf="@+id/radioGroup"
android:layout_toEndOf="@+id/radioGroup" />
</RelativeLayout>
And the Activity Code:
package com.example.portraitvlandscape;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import static java.lang.Math.pow;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//For Button presses (linked via onClick attribute)
public void HandleClick(View arg0) {
double inputRate = 0.0;
double convertedRate = 0.0;
EditText inputText = (EditText)findViewById(R.id.editRate);
TextView convertedText = (TextView)findViewById(R.id.textResult);
try {
inputRate = Double.parseDouble(inputText.getText().toString())/100.0;
} catch (Exception ex) {
inputText.setText("0.0");
}
if(((RadioButton)(findViewById(R.id.radioMonthly))).isChecked()) {
//If converting to monthly
convertedRate = (pow((1.0 + inputRate),(1.0/12.0)) - 1.0)*100.0;
} else {
//Converting to yearly
convertedRate = (pow((1.0 + inputRate), 12) - 1.0) * 100.0;
}
convertedText.setText(String.format("Converted Rate is %1$.4f%%", convertedRate));
}
}
Handling Android Portrait v Landscape Screens
Here are different solutions to handling orientation switching. In summary they are:
- Restrict the app to use only portrait (or landscape) screens via the Android manifest file.
- Drop the portrait design layout into a ScrollView.
- Design a landscape layout.
Screen Orientation Restrict in AndroidManifest.xml
Android can be restricted to not switch the screen to landscape when rotated. Open the AndroidManifest.xml file, in the activity
declaration element add the attribute screenOrientation
and set it to portrait.
<activity android:name=".MainActivity" android:screenOrientation="portrait">
The screen will no longer rotate when the device is turned.
Using a ScrollView to Support Landscape
Is there a more user friendly solution? Instead of using the screenOrientation attibute a quick fix is to drop the entire layout into a ScrollView. When doing this remember to move the xmlns:android
attribute from the first layout element to the ScrollView element (as well as the designer related attibutes xmlns:tools
and tools:context
if present). It has to be the entire layout because ScrollView is derived from FrameLayout
which only accepts a single child. Open the layout file and add the ScrollView (use the Text tab to switch to text editing). Remember to remove android:screenOrientation="portrait" if it was previously added to the AndroidManifest.xml file:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:context="com.example.portraitvlandscape.MainActivity" >
<RelativeLayout
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin" >
<!--– The other elements. –-->
</RelativeLayout>
</ScrollView>
The previously hidden TextView in landscape orientation can be scrolled into view.
Using a Landscape Layout File
A good solution is to explicitly support the landscape orientation. To do this create a folder under the res
directory called layout-land. Copy the existing layout XML file from the res/layout
folder into the new folder. It can be helpful to switch to project view to achieve this:
Then change the copied file, in this case activity_main.xml, in layout-land to suit the landscape orientation.
This is the modified layout file XML.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
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="com.example.portraitvlandscape.MainActivity" >
<TextView
android:text="Convert Interest Rates"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textTitle"
android:textSize="20sp"
android:textStyle="normal|bold"
android:layout_centerHorizontal="true" />
<TextView
android:text="Rate to Convert %"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView"
android:textSize="18sp"
android:layout_alignBaseline="@+id/editRate"
android:layout_alignBottom="@+id/editRate"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<RadioGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/radioGroup"
android:layout_below="@+id/editRate" >
<RadioButton
android:text="Yearly to Monthly"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/radioMonthly"
android:textSize="18sp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:checked="true"
android:layout_weight="1" />
<RadioButton
android:text="Monthly to Yearly"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/radioYearly"
android:textSize="18sp"
android:layout_below="@+id/radioMonthly"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginTop="14dp"
android:layout_weight="1" />
</RadioGroup>
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="numberDecimal"
android:id="@+id/editRate"
android:width="100dp"
android:text="0.0"
android:layout_below="@+id/textTitle"
android:layout_toRightOf="@+id/radioGroup"
android:layout_toEndOf="@+id/radioGroup" />
<Button
android:text="Convert"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button"
android:onClick="HandleClick"
android:layout_alignTop="@+id/textView"
android:layout_toRightOf="@+id/editRate"
android:layout_toEndOf="@+id/editRate"
android:layout_marginLeft="37dp"
android:layout_marginStart="37dp" />
<TextView
android:text="Press Convert for % Result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textResult"
android:textSize="18sp"
android:layout_weight="1"
android:layout_marginRight="36dp"
android:layout_marginEnd="36dp"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
</RelativeLayout>
The great thing here is that there were no code changes required to support the landscape orientation, only copying and reworking the original portrait screen design. The code is available in portrait-landscape.zip for download with an instructions.txt on how to import the project into Studio.
See Also
- See the other Android example apps, projects, code and articles on Tek Eye.
- Tek Eye has more Android articles listed in the full website Index.
- After importing a project to Studio if a Rendering Problems message is displayed when viewing layouts see the article Android Studio Rendering Problems.
- If an error Minimum Supported Gradle Version is shown see the article Minimum Supported Gradle Version Error in Studio.
Archived Comments
psingh on Feb 08, 2017 at 7:40 am said: Really good post, anyone can easily learn.
Author:Daniel S. Fowler Published: Updated: