Scrollable form in Android when the virtual keyboard is open

Modern mobile phones and tablets use virtual keyboards to let users type in input fields. The limited surface along with the virtual keyboard usually leaves a narrow space (viewport) for the input fields.

Android has done a good job with the navigation through input controls when the viewport is limited. Usually there is a button "Next" in the virtual keyboard that lets users scroll to the next input field. When the visible area is very narrow, Android uses its own design layout and shows only the current input field.

But what if you want your users to be able to scroll up? Native controls won't give you that option. The only other way is to use a ScrollView the way we will describe it in this article.

The solution for Android is simple. Design what you need and then wrap it in a ScrollView control. The only tricky detail that may worry you for a while is that ScrollView controls allow one child element only. Easy answer for that one too: use a layout control under the ScrollView to wrap your elements.

In principle, we have a layout like:

<RelativeLayout>
	<TextView 1 />
	<EditText 1 />
	<TextView 2 />
	<EditText 2 />
	<TextView 3 />
	<EditText 3 />
</RelativeLayout>

And we want to transform it to:

<RelativeLayout>
	<ScrollView>
		<RelativeLayout>
			<TextView 1 />
			<EditText 1 />
			<TextView 2 />
			<EditText 2 />
			<TextView 3 />
			<EditText 3 />
		</RelativeLayout>
	</ScrollView>
</RelativeLayout>

All of this work can be done either via raw XML code or the IDE. We recommend you use the XML code because it is a much cleaner way.

So let's see the simplified code above in a real world example. Let's assume that you have this code:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="com.example.app.MainActivity$PlaceholderFragment">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/name"
        android:id="@+id/label_name"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/edit_name"
        android:singleLine="true"
        android:layout_below="@+id/label_name"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/email"
        android:id="@+id/label_email"
        android:layout_marginTop="20dp"
        android:layout_below="@+id/edit_name"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:inputType="textEmailAddress"
        android:id="@+id/edit_email"
        android:layout_below="@+id/label_email"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/message"
        android:id="@+id/label_message"
        android:layout_marginTop="20dp"
        android:layout_below="@+id/edit_email"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:inputType="textMultiLine"
        android:id="@+id/edit_message"
        android:layout_below="@+id/label_message"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true" />

</RelativeLayout>

Inject an additional ScrollView and layout element:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="com.example.app.MainActivity$PlaceholderFragment">

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/scrollView"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/name"
                android:id="@+id/label_name"
                android:layout_alignParentTop="true"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true" />

            <EditText
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/edit_name"
                android:singleLine="true"
                android:layout_below="@+id/label_name"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_alignParentRight="true"
                android:layout_alignParentEnd="true" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/email"
                android:id="@+id/label_email"
                android:layout_marginTop="20dp"
                android:layout_below="@+id/edit_name"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true" />

            <EditText
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:inputType="textEmailAddress"
                android:id="@+id/edit_email"
                android:layout_below="@+id/label_email"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_alignParentRight="true"
                android:layout_alignParentEnd="true" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/message"
                android:id="@+id/label_message"
                android:layout_marginTop="20dp"
                android:layout_below="@+id/edit_email"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true" />

            <EditText
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:inputType="textMultiLine"
                android:id="@+id/edit_message"
                android:layout_below="@+id/label_message"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_alignParentRight="true"
                android:layout_alignParentEnd="true" />

        </RelativeLayout>

    </ScrollView>

</RelativeLayout>

Now your form is scrollable. Users can touch and drag the screen up and down while the virtual keyboard is open.

This article is written for Android apps. The follow up article will show you how to do the same in iOS. iOS does not have any provision for this kind of a problem so our next article is much more useful for iOS programmers.