Developer

Pro tip: Use a custom layout to badge Android's action bar menu items

Developer William J. Francis shares his straightforward solution for badging inside an app on an Android action bar icon.

ice-cream-sandwch-tron.jpg

Badging is a frequently used technique in mobile applications to indicate multiple occurrences of the same event.

chatwfrancis080614.png

We see it quite a bit with application icons (such as the one shown above), but recently I received a request from an art director to create a similar effect inside an app on an Android action bar icon. In the context it was presented it seemed like a good idea, so I proceeded to look into how I might go about achieving the desired UX. As it turns out, it wasn't that difficult.

The tutorial below will step you through the process, or, download and import the entire project into Eclipse.

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

2. In your /res/drawable-xhdpi folder, add an image you wish to use as your icon. I chose a smiley face.

smilingfacewfrancis080614.png

3. Create a custom layout in the /res/layout folder -- this will be for our badge. It is a relative layout that needs to hold both our image and a counter.

badge_layout.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="48dp"
    android:layout_height="fill_parent"
    android:layout_gravity="right" >

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:clickable="true"
        android:src="@drawable/smiley"/>

    <TextView
        android:id="@+id/counter"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:padding="8dp"
        android:text=""
        android:textSize="10sp"
        android:textColor="#ffffff" />

</RelativeLayout>

4. In the same folder, the activity_main.xml file has been edited to wrap a button.

main_activity.xml
<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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.authorwjf.stinkingbadges.MainActivity" >

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="+ 1"/>

</RelativeLayout>

5. In the /res/menu folder, I created an action menu item that references our custom layout.

main.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:id="@+id/badge"
        android:actionLayout="@layout/badge_layout"
        android:title="Badges"
        android:showAsAction="always">
    </item>
</menu>

6. Now all that is left is to write a bit of code. In the /src folder, open MainActivity.java. In the on create we will use an anonymous listener to handle incrementing the reference to the menu item stored in the on create options menu override.

MainAcitvity.java
package com.authorwjf.stinkingbadges;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class MainActivity extends Activity {

	private TextView mCounter;
	private int count=0;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		findViewById(R.id.button).setOnClickListener(new OnClickListener(){

			@Override
			public void onClick(View v) {
				if (mCounter!=null) {
					count++;
					mCounter.setText("+"+Integer.toString(count));
				}
			}});
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.main, menu);
		RelativeLayout badgeLayout = (RelativeLayout) menu.findItem(R.id.badge).getActionView();
		mCounter = (TextView) badgeLayout.findViewById(R.id.counter);
		return true;
	}
}

As promised, it's fairly straightforward and easily extended if needed. Load it up on a device or emulator and give it a try for yourself.

badgeswfrancis080614.png

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...

1 comments
anafaria10
anafaria10

Hello. Followed the tutorial and everything is working as expected, but I am not able to make the badge clickable. I'm guessing it's because of the use of a layout. Is there a way around it? Thanks in advance.

Editor's Picks