Today we’re going to continue 31 Days of Android by starting to talk about two different ways to display more information than will fit on the screen:  ScrollViews and ListViews.  Today we will focus on ScrollViews and tomorrow will be ListViews.  Due to the way these two Views work, you don’t want to combine the two of them.  Once I’ve gone over both off them tomorrow, I’ll talk about why you should keep them separate.  You can download the sample code we’re going to start today with here.

The ScrollView

The ScrollView enables you to create screens that very closely resemble a web page.    Adding a scroll view to a layout allows you to let the user scroll anything within the ScrollView vertically and horizontally.  If you run your app right now, you’ll see there isn’t any need for scrolling: 

Android No Scrollview

However, if you were to add a huge amount of text at the bottom, that might change.  Open your res/values/strings.xml file and add a new String.  Name it big_text and put a very huge text String in there.  Something like this:

<string name="big_text">Cow ... tongue</string>

In order to make your string suitably long, I’d recommend getting a few paragraphs from Bacon Ipsum.  Now open the res/layout/main.xml layout file.  You need to add a new TextView beneath the last button and set it to your big_text value.  When you’re done you should have something like this:

<TextView
    android:id="@+id/lblTextViewBig"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/big_text" />

Now when you run your app, you’ll notice that the text goes off the screen and you don’t have anyway to view it:

Too much text in a view

Here’s where you can use the ScrollView.  Your first instinct may be to go back to your layout and change the LinearLayout at the root to a ScrollView.  If you do that, you’ll be greeted by this unpleasant error:

Caused by: java.lang.IllegalStateException: ScrollView can host only one direct child

This means that you can’t have more than one View as a child of the ScrollView.  Since your layout has a couple TextViews, an EditText, and a couple Buttons, you can’t just replace the root LinearLayout like this.  What you can do though is wrap the LinearLayout inside of a ScrollView.  This allows you to have a single child beneath the ScrollView but have multiple children beneath that.  When you’re done, your XML should look like this:

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:fillViewport="true" >
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >
        <TextView
        ...

Now when you run your app, you’ll be able to tap on the screen and drag up:

Android Screen with ScrollView

Notice that when you scroll you’ll see a scrollbar on the right side of the screen.  You’ll notice that you can’t scroll right or left.  This is because the ScrollView only supports vertical scrolling.  The HorizontalScrollView element will allow you to scroll horizontally.  It is possible to put a HorizontalScrollView in as the child of the VerticalScrollView which will allow you to scroll in both directions, however, Google says this is a bad idea.  Instead, they suggest you override ScrollView and create your own control capable of both vertical and horizontal scrolling.  This is entirely possible and if you search the internet, you’ll find several examples of people doing this and even the source code for their implementations.  As I like to do, I’d remind you to remember that just because you can do it, doesn’t mean you should.  The experience when you have to scroll in multiple directions on a small screen device isn’t a very good one (yes the WebView and browser give you this capability and I’d argue whether I like that sometimes). 

There are a number of different attributes you can use in a ScrollView including ones that let you change how the scrollbars look, how long they’re visible, if they’re visible, etc.  In addition, you can control the scrolling of your ScrollView programmatically if you want to.  For example, if you wanted to add a Button that would trigger the ScrollView to scroll to the top, this is possible by doing the following:

ScrollView scrollViewOne = (ScrollView) findViewById(R.id.scrollViewOne);
scrollViewOne.scrollTo(0,  0);

Here you’re getting a reference to your ScrollView and telling it to scroll back to the top left corner.  Another important thing about the ScrollView is that it doesn’t have to be the root element in your layout.  If you wanted to have a text header at the top of the screen that your scroll view wouldn’t encompass, you could just put the ScrollView in as a child of the root LinearLayout.  Here’s your layout XML where the ScrollView is only wrapping the big_text TextView:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <TextView
        android:id="@+id/lblTextViewOne"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />
    ...
    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button" />
    <ScrollView
        android:id="@+id/scrollViewOne"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >
        <TextView
            android:id="@+id/lblTextViewBig"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="@string/big_text" />
    </ScrollView>
</LinearLayout>

You should be ready to use ScrollViews in your own applications now.  Tomorrow we’ll go over the other method of displaying a lot of information in a single page, ListViews. 

You can download the source code from today here.


Chris Risner