id="info"

Developer

How to maximize Android screen real estate by showing and hiding the action bar

Another handy tool to put in your bag of Android UI tricks is smartly managing the persistence of the action bar. Here's how.

zdnet-android-kitkat-620x409.jpg

Honeycomb's introduction of the action bar widget went a long way to improving user experience on Android devices. However, the fact remains users want to do a lot on a screen that in most cases is less than five inches tall. Google validated the periodic need for an application to utilize the entire screen efficiently with the introduction of immersive mode in KitKat.

On occasion I have found that deciding whether an app should present the user with a fully immersive experience or a more traditional persistent navigation layout is not always a matter of either or. There are times when the best choice is smartly presenting the action bar based on user gestures. A good example is when scrolling through a list where the action bar has no contextual significance. The video below demonstrates what I mean.

Achieving the same type of reactive action bar in your own app is not incredibly difficult. The code below will show you how. Feel free to follow along, or download and import the entire project directly into Eclipse.

1. Start a new Android project in Eclipse. Target SDK 14 (ICS) or better.

2. For the purpose of this demonstration I've included three large images in my /res/drawable-xhdpi folder titled appropriately.

androidnumber1062614.png

androidnumber2062614.png

androidnumber3062614.png

3. In the /res/layout folder I have modified activity_main.xml to include a scroll view that wraps a linear layout. The linear layout includes our three images. Note the padding applied to the top of the linear layout. This is how we can access the height of our action bar at design time.

activity_main.xml
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/parent">
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingTop="?android:attr/actionBarSize" 
        android:orientation="vertical">

	    <ImageView 
	        android:id="@+id/first_item"
	        android:layout_margin="20dp"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:src="@drawable/number_1"/>
	    
	    <ImageView 
	        android:layout_margin="20dp"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:src="@drawable/number_2"/>
	    
	    <ImageView 
	        android:layout_margin="20dp"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:src="@drawable/number_3"/>
	    
    
    </LinearLayout>
    
</ScrollView>

4. With our resources in place now we are ready to write some code. While the actual hiding and showing of the action bar happens in the on scroll changed handler, the magic happens in our on create override. First is the addition of the flag FEATURE_ACTION_BAR_OVERLAY to the main window. This prevents the parent from laying out the children each time we hide and show the action bar. The second noteworthy call is attaining the size of the action bar via the applied theme. This is the java equivalent of: ?android:attr/actionBarSize.

MainActivity.java
package com.authorwjf.reactiveactionbar;

import android.os.Bundle;
import android.app.ActionBar;
import android.app.Activity;
import android.content.res.TypedArray;
import android.view.Menu;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.widget.ScrollView;

public class MainActivity extends Activity implements ViewTreeObserver.OnScrollChangedListener {

	private float mActionBarHeight;
	private ActionBar mActionBar;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		getWindow().requestFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
		setContentView(R.layout.activity_main);
		final TypedArray styledAttributes = getTheme().obtainStyledAttributes(
                new int[] { android.R.attr.actionBarSize });
		mActionBarHeight = styledAttributes.getDimension(0, 0);
    	styledAttributes.recycle(); 
    	mActionBar = getActionBar();
		((ScrollView)findViewById(R.id.parent)).getViewTreeObserver().addOnScrollChangedListener(this);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public void onScrollChanged() {
		float y = ((ScrollView)findViewById(R.id.parent)).getScrollY();
		if (y >= mActionBarHeight && mActionBar.isShowing()) {
			mActionBar.hide();
		} else if ( y==0 && !mActionBar.isShowing()) {
			mActionBar.show();
		}
	}

}

That's it. You can load the demo app to a device or emulator and check it out for yourself.

I am repeating myself, but keep in mind this convention completely breaks the user experience if your action bar contains a contextual option. For example, if you have a delete option in your action bar, you can't very well hide it, as the user may need to delete an option at the bottom of the list. When carefully considered and used sparingly, though, I find smartly managing the persistence of the action bar a handy tool in my bag of UI tricks.

Also see

About

William J Francis began programming computers at age eleven. Specializing in embedded and mobile platforms, he has more than 20 years of professional software engineering under his belt, including a four year stint in the US Army's Military Intellige...

Editor's Picks