ActionBar design pattern example for Android

ActionBar is a user interface (UI) design pattern found in Android that allows users to quickly perform common actions within your application. ActionBar replaces the traditional title bar with a more featured and consistent UI. Popular applications that use this pattern include Facebook App and Twitter App. ActionBars help us to:

  • Have a dedicated UI space for commonly used actions in your applications to increase user engagement (e.g. Search, Refresh, display status etc.)
  • Have a consistent look and feel across all activities
  • Allows the user to perform common/key actions quickly without having to use the menu

Though framework support for ActionBars has been added in Android 3.0+ (Honeycomb), developers are required to implement it from scratch for non-tablet versions of Android. The aims of this tutorial are two-fold; Firstly to demonstrate how to build an ActionBar widget from ground up, and secondly to illustrate how to use the ActionBar in your application.

Figure 1 shows an Activity with the ActionBar we are planning to implement in this tutorial.

Figure 1: Action Bar Example

As shown in the above figure, our ActionBar will have 4 main sections:

  1. Home Icon: A quick an easy way to navigate back to your main Activity from sub-Activities in your applications.
  2. Activity Title: A descriptive text for your Activity (similar to traditional Activity title)
  3. Progressbar Icon: This is used as a visual cue for users when our application is busy doing something in the background. It will not be displayed when application is not busy.
  4. Action Icons: zero or more icons to allow users to perform common actions (e.g. access settings, search etc)

The design (e.g. look & feel, functionality etc.) of the ActionBar layout is not fixed. I chose the structure shown in Figure 1 above purely because that was simple to explain in this tutorial. I designed the ActionBar as a widget in order to make my implementation easy to reuse.

The tutorial is broken down into 3 parts:

  1. Define the ActionBar layout
  2. Implement the code for ActionBar widget
  3. Including the ActionBar widget in your application

Define the ActionBar layout in XML

The full XML layout for actionbar.xml file (goes in res\layout folder) is shown in the code snippet below.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="fill_parent" 
	android:layout_height="@dimen/actionbar_height"
	android:layout_marginBottom="2dip">
	<ImageView android:id="@+id/actionbar_home_logo"
		android:layout_alignParentLeft="true" 
		android:layout_width="wrap_content"
		android:layout_height="fill_parent" 
		android:background="@drawable/actionbar_btn"
		android:padding="0dip" />
	<LinearLayout android:id="@+id/actionbar_actionIcons"
		android:layout_width="wrap_content" 
		android:layout_height="@dimen/actionbar_height"
		android:layout_alignParentRight="true" 
		android:layout_centerVertical="true"
		android:layout_margin="0dp" android:padding="0dp"
		android:background="@color/actionbar_separator" />
	<ProgressBar android:id="@+id/actionbar_progress"
		android:layout_width="wrap_content" 
		android:layout_height="wrap_content"
		android:layout_toLeftOf="@id/actionbar_actionIcons"
		android:layout_centerVertical="true" android:paddingRight="7dip"
		android:indeterminateOnly="true" android:visibility="gone"
		style="@android:style/Widget.ProgressBar.Small" />
	<TextView android:id="@+id/actionbar_title"
		android:layout_width="wrap_content" 
		android:layout_height="fill_parent"
		android:layout_toRightOf="@id/actionbar_home_logo"
		android:layout_toLeftOf="@id/actionbar_progress" 
		android:paddingLeft="10dip"
		android:paddingRight="10dip" android:textSize="16dip"
		android:textStyle="bold" android:textColor="@color/actionbar_title"
		android:lines="1" android:ellipsize="marquee"
		android:marqueeRepeatLimit="marquee_forever" />
</RelativeLayout>

The layout is a RelativeLayout with 4 child elements; an ImageView to display the home icon, a TextView to display the title, a ProgressBar to display the busy icon and a LinearLayout to display application-specific ActionIcons.

There are few points that I would like to draw your attention to:

  • @drawable/actionbar_btn in line #10 is used to define a selector element to define the background colour depending on the state of the button (e.g. normal, pressed, focused etc). You can read more about it from here.
  • The progressbar styling used in line #25 enables us to display the small busy icon shown in Figure 1. Have a look at Android documentation if you feel like experimenting with available styles.
  • I am not defining any icons in the widget xml layout for home-icon or ActionIcons because this is meant to be a reusable widget. I will show later on how applications can specify their own icon resources to customise the widget.

Implement the code for ActionBar widget

The next is to implement the logic for the ActionBar widget in Java code. The code snippet below shows the constructor and an overview of the key functionality exposed by the widgets (using the public methods). The most important thing to note is that our ActionBar class extends android.widget.RelativeLayout, which has a single root element: the previously discussed xml layout.

public class ActionBar extends RelativeLayout {

	/**
	 * Reusable {@link LayoutInflater}
	 */
	private LayoutInflater mInflater;
	/**
	 * Holds the home-icon logo
	 */
	private ImageView mLogoView;
	/**
	 * Displays the {@link Activity} text
	 */
	private TextView mTitleView;
	/**
	 * Represents the progress bar (i.e. busy-icon)
	 */
	private ProgressBar mProgress;
	/**
	 * Contains the ActionIcons.
	 */
	private LinearLayout mActionIconContainer;

	public ActionBar(Context context, AttributeSet attrs) {
		super(context, attrs);

		mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

		RelativeLayout barView = (RelativeLayout) mInflater.inflate(R.layout.actionbar, null);
		addView(barView);

		mLogoView = (ImageView) barView.findViewById(R.id.actionbar_home_logo);
		mProgress = (ProgressBar) barView.findViewById(R.id.actionbar_progress);
		mTitleView = (TextView) barView.findViewById(R.id.actionbar_title);
		mActionIconContainer = (LinearLayout) barView.findViewById(R.id.actionbar_actionIcons);
	}

	/**
	 * Setters for home icon
	 */
	public void setHomeLogo(int resId) { ... }	
	public void setHomeLogo(int resId, OnClickListener onClickListener) { ... }

	/**
	 * Setters for Activity title
	 */
	public void setTitle(CharSequence title) { ... }
	public void setTitle(int resid) { ... }

	/**
	 * Setters for displaying/hiding the progress bar
	 */
	public void showProgressBar() { ... }
	public void hideProgressBar() { ... }
	public boolean isProgressBarVisible() { ... }

	/**
	 * Adds ActionIcons to the ActionBar (adds to the left-end)
	 * 
	 * @param iconResourceId
	 * @param onClickListener to handle click actions on the ActionIcon.
	 */
	public void addActionIcon(int iconResourceId, 
		OnClickListener onClickListener) { ... }

	/**
	 * Removes the action icon from the given index
	 * 
	 * @param index 0-based index corresponding to the ActionIcon to remove
	 * @return <code>true</code> if the item was removed
	 */
	public boolean removeActionIconAt(int index) { ... }
}

The private variables are used to perform the logic for the public functions defined earlier. For example, the method body to add an action icon would look like follows:

	public void addActionIcon(int iconResourceId, OnClickListener onClickListener) {
		// Inflate
		View view = mInflater.inflate(R.layout.actionbar_icon, mActionIconContainer, false);
		ImageButton imgButton = (ImageButton) view.findViewById(R.id.actionbar_item);
		imgButton.setImageResource(iconResourceId);
		imgButton.setOnClickListener(onClickListener);

		mActionIconContainer.addView(view, mActionIconContainer.getChildCount());
	}

One thing to note in line #3 in the above method is that I am using another layout called actionbar_icon to describe what an ActionIcon is. This is simply a xml file, as shown below, which defines the common attributes for an ActionIcon. I could have used an ImageButton here instead, but opted for a separate layout to minimise the amount of code I otherwise would have to write (e.g. to set the layout attributes etc.)

<?xml version="1.0" encoding="utf-8"?>
<ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
	android:id="@+id/actionbar_item" android:layout_width="44dip"
	android:scaleType="fitXY" android:layout_height="44dip"
	android:background="@drawable/actionbar_btn" android:padding="4dip"
	android:layout_marginLeft="1dip" android:layout_centerVertical="true"
	android:singleLine="true" android:visibility="visible" />

Including the ActionBar widget in your application

Now the ActionBar widget is defined, the final step is to include it in a sample Android application. There are several ways to replace the default Activity title bar with our ActionBar as shown below.

  1. Hide the default title bar and include the ActionBar as a View: This involves requesting the Activity to display without the default title (see code snippet for MainActivity class below) and including the ActionBar widget in the Activity’s layout xml.
    public class MainActivity extends Activity {
    	@Override
    	public void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		// prevent the default title-bar from beig displayed
    		requestWindowFeature(Window.FEATURE_NO_TITLE);
    		setContentView(R.layout.main_activity);
    
    		// ... code omitted for brevity
    	}
    	...
    }
    
    <!-- code snippet for the MainActivity's layout file 
      -- (main_activity.xml)  -->
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    	android:layout_width="fill_parent" 
    	android:layout_height="fill_parent">
    	<com.thira.examples.actionbar.widget.ActionBar
    		android:id="@+id/actionBar" 
    		android:layout_width="fill_parent"
    		android:layout_height="45dip" 
    		android:layout_alignParentLeft="true"
    		android:layout_alignParentTop="true" />
    	<!-- rest of the views goes below the ActionBar widget -->
    </RelativeLayout>
    
  2. Replace the default title bar with ActionBar: We first need to define a xml layout for the custom title (custom_title.xml) and then specify the Activity to use that layout to decorate the title bar (see CustomTitleActivity class).
    <!-- code snippet for the custom title layout 
      -- (custom_title.xml)  -->
    <?xml version="1.0" encoding="utf-8"?>
    <com.thira.examples.actionbar.widget.ActionBar
    		xmlns:android="http://schemas.android.com/apk/res/android" 
    		android:id="@+id/actionBar" 
    		android:layout_width="fill_parent"
    		android:layout_height="45dip" 
    		android:layout_alignParentLeft="true"
    		android:layout_alignParentTop="true" />
    
    public class CustomTitleActivity extends Activity {
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		// set a custom layout as the title bar
    		requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
    		setContentView(R.layout.custom_title_activity);
    		getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title);
    
    		// ... code omitted for brevity
    	}
    	...
    }
    

After including the ActionBar (using either of the two methods mentioned above) in an Activity, you can customise it to suit your specific needs. The code snippet below shows setting the title, home icon and one ActionIcon when the Activity is created.

public class MainActivity extends Activity {
	private ActionBar mActionBar;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		// .. . setup code goes in here

		mActionBar = (ActionBar) findViewById(R.id.actionBar);
		mActionBar.setTitle(R.string.app_name);
		// set home icon that does nothing when the user clicks on it
		mActionBar.setHomeLogo(R.drawable.ic_title_home_default);
		// sets an action icon that displays a Toast upon clicking
		mActionBar.addActionIcon(R.drawable.ic_settings2, 
			new OnClickListener() {
				@Override
				public void onClick(View v) {
					Toast.makeText(MainActivity.this, 
						"Clicked on an ActionIcon", 
						Toast.LENGTH_SHORT).show();
				}
			});
	}

Final Remarks

It has been a tedious read, but hopefully you will be in a position to use this tutorial as a starting point to write your own ActionBars. Please do not hesitate to ask any questions that you might have! I will try my best to answer them in a timely manner.

Download Links for the source code:

17 responses to “ActionBar design pattern example for Android

  1. Nice tutorial. Well written and very easy to follow even for non-technical peeps.

  2. heyThiranjith,
    nice tutorial.
    is there any link to download this project?

  3. Thanks dude
    I reaaly appreciate ur work

  4. it doesnt work!

  5. Hi, i have a question, lets suppose that your Application has multiple activities and the user is constantly switching between them, how can your ActionBar persist across them? do i have to define it in every layout XML for each activity?
    Thanks in advance

    • Hi,

      The ActionBar is just another widget (like Buttons or TextViews) that is part of your Activity’s layout. When Android draws your Activity on screen, it will draw whatever you’ve specified in that Activity’s layout; including the ActionBar widget. That means, each Activity will have its own instance of ActionBar widget.

      If you want to persist state information related to your ActionBar between Activities, you will have to pass the necessary flags/information via the Intent you create to start a new Activity (these will be accessible to the new Activity via the Bundle argument in onCreate method).

      If you want to reuse the same ActionBar widget across multiple activities then you have to (a) add it to each Activity’s layout xml (like you suggested) and (b) populate its properties after obtaining a reference to it (ActionBar) as I illustrated in the article above.

      You can use several techniques to make your solution more modular:
      1) Reuse layouts to ensure all your Activities have the ActionBar (see http://android-developers.blogspot.com/2009/02/android-layout-tricks-2-reusing-layouts.html and http://developer.android.com/resources/articles/layout-tricks-reuse.html)
      2) Have an abstract Activity class that handles the crud operations related to your ActionBar widget (e.g. changing title, other context-specific items such as enable/disable buttons, show icons etc.)

      Hope that cleared out things a little bit. Feel free to ask me any other questions that you might have.

      Cheers,
      Thira.

  6. Exactly what I was looking for in my project, Thanks so much!

  7. Useful tutorial. Good work!

  8. Easy to implement. Nice!

  9. Hi, i have an abstract class which is supposed to handle all the operations of the action-bar. Problem is Java does not support multiple inheritance. i have already extended List-view activity and i also want to extend the abstract class. Is there another way i can solve this issue instead of defining the functions of that action bar in each activity i an creating i.e for them to be in one class and then reuse them in each activity.

    • There are several ways to address this depending on what your other Activities are like. If they all extend ListView, the you can make your abstract class (that performs action-bar related tasks) extend ListView, and your Activities extend the abstract class.

      Otherwise (i.e. your Activities extend different super classes, which I assume the case is with you), you can wrap the common operations relating to ActionBar in a helper class. Then you can use the helper class in all the Activities you want to perform that functionality irrespective of the class hierarchy!

      You can find examples of using helper classes throughout Android SDK. SQLiteOpenHelper (for performing db tasks in Android) is one such example. see http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html

      Let me know if you still have any questions.

      Cheers!

  10. i have tried importing thira-blog-demos-3182731/android-actionbar-example-v1 into my eclipse IDE but it shows errors everytime in src and res/values folders . The errors are like

    import com.thira.examples.actionbar.widget.ActionBar; cannot be resolved

    private ActionBar mActionBar; cannot be resolved

    leading to all sorts of errors

  11. Bugs everywhere. Through the whole project.
    I am using android 4.0 SDK. Is there sth. wrong with my SDK version.

Leave a comment