Tek Eye Logo

Tek Eye

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.

Portrait v Landscape

(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.)

Mike Bugdroid the Android Logo

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).

Portrait Screen in Android

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.

Cut Off Android Landscape Screen

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.

No Screen Change on Rotation to Landscape

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.

ScrollView to Correct Landscape Screen

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:

Landscape Layout Resource File in Android Studio Project View

Then change the copied file, in this case activity_main.xml, in layout-land to suit the landscape orientation.

Android Landscape Layout Corrected

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

Archived Comments

psingh on Feb 08, 2017 at 7:40 am said: Really good post, anyone can easily learn.

Author:  Published:  Updated:  

ShareSubmit to TwitterSubmit to FacebookSubmit to Google+Submit to LinkedInSubmit to redditPrint Page

markdown CMS Small Logo Icon ↓markdown↓ CMS is fast and simple. Build websites quickly and publish easily. For beginner to expert.



Articles on:

Android, HTML, VPS, Computing, IT, Computer History, ↓markdown↓ CMS



Free Android Sample Projects:

Android Examples, Android UI Examples