Thursday, January 29, 2009

Android View XML

I am thoroughly enjoying using XML to define the view characteristics of my Android application. I've written GUI code in Visual Basic, Swing, RCP, and a dab of GTK+. None of them are as easy and elegant as using XML. I applaud the Android team in using this approach.

Don't forget to apply some style to your view. Who would want to look at some boring, white standard font. Checkout the Android documentation on styles and themes.

But don't stop at using only the view components that Android supplies. Good object oriented design encompasses creating custom view components for your custom data objects. If you have a domain object called Person that needs to be displayed then you should have a custom composite view that knows exactly how a Person is displayed -- err, the attributes of the person are displayed. I learned over here that using custom view controls in the XML is as easy as defining an xml element with the name of your custom view.

I put together the below example as a guide. It is not meant to be an exemplar. Note that i have a LinearLayout that defines padding. That likely belongs in a style instead of being defined solely for THAT LinearLayout. With that warning in place, here's an exmple of a my.app.PersonComposite which is a custom class that extends LinearLayout. To use this custom view component in your XML then you would include something like the following:
<my.app.PersonComposite
android:id="@+id/person"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
So, that element will put a PersonComposite in your activity. But what does the PersonComposite look like? Well, that should be defined in xml as well. In the constructors of PersonComposite, include the following:
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View inflatedView = inflater.inflate(R.layout.person_composite, this);

In order for this to work, you'll need to have a ./res/layout/person_composite.xml. Perhaps something like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:padding="2dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<TextView
style="@style/BigAndBlue"
android:id="@+id/personLastName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/not_given_default"
/>

<TextView
android:id="@+id/personFirstName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/not_given_default"
/>
</LinearLayout>
Note that the style attribute conspicuously lacks the android namespace. Hmm? Oh well, just watch out for that. We have to define that Style over in ./res/values/styles.xml:
<resources>
<style name="BigAndBlue">
<item name="android:textSize">12pt</item>
<item name="android:textColor">#008</item>
</style>
</resources>

3 comments:

noodle said...

This has helped be a bit but would help me a lot more if you could post some source code. Is this possible?

noodle said...

Ok, I found my issue. I had to include both constructors, not just one. Thanks, your post was very helpful to me.


public NumberSpinner(Context context) {
super(context);

LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View inflatedView = inflater.inflate(R.layout.number_spinner, this);
}

public NumberSpinner(Context context, AttributeSet att) {
super(context,att);

LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View inflatedView = inflater.inflate(R.layout.number_spinner, this);
}

James Wilson said...

Good to hear. I'm glad it helped.