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.
As shown in the above figure, our ActionBar will have 4 main sections:
- Home Icon: A quick an easy way to navigate back to your main Activity from sub-Activities in your applications.
- Activity Title: A descriptive text for your Activity (similar to traditional Activity title)
- 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.
- 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:
- Define the ActionBar layout
- Implement the code for ActionBar widget
- Including the ActionBar widget in your application
Define the ActionBar layout in XML
The full XML layout for actionbar.xml
file (goes in reslayout
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.
- 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>
- 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 (seeCustomTitleActivity
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:
- ActionBar widget library: https://github.com/thira/blog-demos/tree/master/android-actionbar-lib-v1
- Example application (using the library): https://github.com/thira/blog-demos/tree/master/android-actionbar-example-v1
NOTES:
The MainActivity
of the example application demonstrates the first approach of using the ActionBar, and allows you to show/hide the progress bar as well as add/remove ActionIcons. The CustomTitleActivity
demonstrates how to use ActionBar in place of the default toolbar. Feel free to play around and modify the code as you see fit!