Smartphones

'Cutting corners' on Android's default list view widget

Here's a tutorial on how to add the rounded buttons to the Android interface.

Designing user interfaces is tricky business. People like what they like. You may be a big fan of Apple’s rounded buttons and bubble-like widgets or you may prefer the stark sharp edges of the Metro UI running on Windows Phone 7. I’m not a GUI guy. I cut my teeth on PCs back in the day when the command line was king and I’m not particularly married to any one school of thought when it comes to user interfaces. So when I was approached about putting rounded corners on Android’s default list view widget I dove right in.

After a couple false starts, eventually I had a list view with both rounded corners and a nice gradient background as well. I decided to share the source code with you because as I was poking around in various Android development-related forums searching for clues, I encountered a lot of incomplete answers, and even a bit of hostility. It seems there are some developers who believe if you ever feel the urge to round the corners on a widget you should immediately take your Google phone back to the store you bought it from and ask for an iPhone.

I wholeheartedly concur that consistency across a platform, particularly in terms of the user interface, just makes good sense. At the same time, I’m not naïve enough to believe that doing something a little different is never the “right” design choice. Mobile developers are creating something that has to get noticed in a sea of apps (on Google’s platform that number is more than 200,000 and counting). If adding a little “bling” to your UI gets users excited about your app, I say more power to you.

The tutorial that follows can be built against version 1.6 and greater of the Android SDK. Alternatively you may download the complete project here and just import it into Eclipse. Either way, I hope you will take a few minutes to look at the code, see how it works, and add some knowledge to your programming arsenal. And remember, whether you prefer square corners on your lists or rounded ones, we’re all geeks on the inside. Live and let live--that’s my motto!

1. Create a new Android project in Eclipse.

2. In the /res folder create a new directory called /xml.

3. We’ll be adding four xml files, all just slight variations of the first. This is for the sake of making the demo all inclusive. In a real project you’d likely just go with a single background resource.

rec.xml <?xml version="1.0" encoding="UTF-8"?>

<shape xmlns:android="http://schemas.android.com/apk/res/android"

android:shape="rectangle">

<solid

android:color="#ffffff"/>

</shape>

faded_rec.xml <?xml version="1.0" encoding="UTF-8"?>

<shape

xmlns:android="http://schemas.android.com/apk/res/android"

android:shape="rectangle">

<gradient android:startColor="#ffffff"

android:endColor="#666666"

android:angle="270"/>

</shape>

rounded_rec.xml <?xml version="1.0" encoding="UTF-8"?>

<shape

xmlns:android="http://schemas.android.com/apk/res/android"

android:shape="rectangle">

<solid

android:color="#ffffff"/>

<corners

android:bottomRightRadius="15dp"

android:bottomLeftRadius="15dp"

android:topLeftRadius="15dp"

android:topRightRadius="15dp"/>

</shape>

faded_rounded_rec.xml

<?xml version="1.0" encoding="UTF-8"?>

<shape

xmlns:android="http://schemas.android.com/apk/res/android"

android:shape="rectangle">

<gradient

android:startColor="#ffffff"

android:endColor="#666666"

android:angle="270"/>

<corners

android:bottomRightRadius="15dp"

android:bottomLeftRadius="15dp"

android:topLeftRadius="15dp"

android:topRightRadius="15dp"/>

</shape>

4. Now that we have the shapes laid out we will need to add a layout for our main activity in the /res/layout folder. It looks long but for the most part it consists of the standard list view and a text view, and a couple check boxes. The only thing out of the ordinary is the inner linearlayout that hosts the list view.

main.xml <?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:gravity="center"

android:layout_gravity="center"

android:layout_margin="10dip">

<TextView

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="Corners and Backgrounds Demo"

android:textColor="#ffffff"

android:textSize="18sp"

android:gravity="center"/>

<CheckBox android:id="@+id/cut_the_corners"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:paddingBottom="6dip"

android:layout_marginTop="4dip"

android:text="Cut the corners."

android:textColor="#ffffff"

android:textSize="15sp"/>

<CheckBox android:id="@+id/fade_the_bg"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:paddingBottom="6dip"

android:layout_marginTop="4dip"

android:text="Fade the background."

android:textColor="#ffffff"

android:textSize="15sp"/>

<LinearLayout

android:id="@+id/list_bg"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:gravity="center"

android:layout_gravity="center"

android:background="@xml/rec"

android:padding="4dip">

<ListView

android:id="@+id/android:list"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:dividerHeight="1dip"

android:layout_gravity="center"

android:background="@android:color/transparent"

android:cacheColorHint="#0000"

android:layout_margin="8dip"

android:gravity="center"

android:focusable="false"/>

</LinearLayout>

</LinearLayout>

GOTCHA—Notice we’ve set the property android:cacheColorHint to transparent. Nowhere in the documentation did I see this clearly explained, yet when you are trying to put a listview over top of any background, you must set this property and in this manner. If you don’t anytime you scroll the list, your custom background will “blink” in and out.

5. One more layout file and then we can get to the code. We’ll need a simple text view defined in the layout folder for our list view line items.

list_view_row.xml <?xml version="1.0" encoding="utf-8"?>

<TextView

xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:padding="10dp"

android:textSize="16sp"

android:textColor="#000000" >

</TextView>

6. Let’s move to the /src folder now and our Main.java class. We’ll start by extending a list activity, and creating a static list to populate our listview. Feel free to use your own static list of text strings if you don’t like mine!

Main.java public class Main extends ListActivity implements OnCheckedChangeListener{

/*top fifteen reasons I stayed in last weekend*/

static final String[] EPISODES = new String[] {

"All Our Yesterdays",

"Amok Time",

"Arena",

"Corbomite Maneuver",

"Day Of the Dove",

"Doomsday Machine",

"Enemy Within",

"Enterprise Incident",

"Errand of Mercy",

"Journey to Babel",

"Mirror, Mirror",

"Space Seed",

"This Side of Paradise",

"The Tholian Web",

"Trouble with Tribbles"

};

}

7. Next we’ll need to override the OnCreate. This is standard Android GUI development. I’m just assigning the layout to the class, hooking the array of strings to the list view adapter, and finally wiring the listeners for the check boxes.

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

setListAdapter(new ArrayAdapter<String> (this, R.layout.list_view_row, EPISODES));

CheckBox cb = (CheckBox)findViewById(R.id.fade_the_bg);

cb.setOnCheckedChangeListener(this);

cb = (CheckBox)findViewById(R.id.cut_the_corners);

cb.setOnCheckedChangeListener(this);

}

8. Last but not least we need to add the logic for handling swapping out the background resource files.

@Override

public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

LinearLayout l = (LinearLayout)findViewById(R.id.list_bg);

CheckBox faded = (CheckBox)findViewById(R.id.fade_the_bg);

CheckBox rounded = (CheckBox)findViewById(R.id.cut_the_corners);

if (!faded.isChecked()&&!rounded.isChecked()) {

l.setBackgroundResource(R.xml.rec);

} else if (!faded.isChecked()&&rounded.isChecked()) {

l.setBackgroundResource(R.xml.rounded_rec);

} else if (faded.isChecked()&&(!rounded.isChecked())) {

l.setBackgroundResource(R.xml.faded_rec);

} else if (faded.isChecked()&&rounded.isChecked()) {

l.setBackgroundResource(R.xml.faded_rounded_rec);

}

}

That’s it. There really isn’t much code because the majority of the work is up front in our layouts. Fire the app up on an emulator or your actual device even and decided for yourself which UI works for you. Am I cutting corners or smoothing out the rough edges? You be the judge.

A square list view.

A rounded list view.

Rounded list view with a gradient.

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

0 comments