9-Patch Image – Designers Vs Developers

I am sure when the Google team came up with the 9-patch image, they must have felt real smug. Engineers excitedly talking around coffee machines about the pure awesomeness of it’s capabilities must have been a common sight. And in all the excitement they conveniently forgot to write all about it and hoped that designers and developers would miraculously figure out how it worked and more importantly how it didn’t.

Fortunately days have improved and there is now some documentation available at http://developer.android.com/guide/topics/graphics/2d-graphics.html#nine-patch, but I might add that it is the bare minimum.

I have also seen numerous cases where the designers and developers have been at each others’ throats trying to figure out who is responsible for all the screwed up 9-patches. So here’s an attempt at spreading peace and bringing the two at the same page.

Where do I use a 9-patch?

There are many situations where in the backgrounds are same though the sizes of the View elements may vary in size. For example backgrounds of buttons whose size depend on the button text size. Backgrounds for ViewGroups whose size vary based on the content. In such situations, adding multiple backgrounds for each of the elements is pointless.

The image below shows how different backgrounds on the left can be replaced by a single, much smaller 9-patch image and yet achieve the same result.

nine_patch_usability

The Basics

Before we go all technical about 9-patch, here are some basics

  • 9-patch image is a Stretchable Bitmap Image.
  • It has a 1-pixel transparent border on which the stretchable and the static areas of the image are defined using black color.
  • It has an extension .9.png. For example, image.9.png.
  • As of now two things can be defined of the image, the SCALABLE Area and the FILL Area (can be also referred to as the padding of the image).
  • TOP/LEFT borders are used to define the scalable areas while BOTTOM/RIGHT is used to specify the fill area.
  • Multiple scalable areas can be specified for the image.

nine_patch_structure

The image above shows all the Scalable and Fill areas. You might find it a little confusing in the beginning but by the time you are done with this, it will all make sense.

The 9-patch structure

Basic structure showing the scalable areas

Basic structure showing the scalable areas (Image scaled from original size to show the patches clearly)

This shows the basic structure of the 9-patch. You will observe that there are 9 divisions and hence the name 9-patch. The four corners remain static and do not scale in any direction. The center-left and center-right areas scale only along the Y-axis while the top-center and bottom-center stretch only along the X-axis. The center of the image stretches in both the X and Y directions.

Creating a 9-patch Image

Below are the steps to create a 9-patch image using Photoshop or any other image editing tool such as GIMP because I am sure most designers would be using one of them. Developers on the other hand wouldn’t. Click here if you are a developer and want to use the Draw 9-Patch tool.

1. Let us say that we want to make an image that is 48×48. So we start of with an image of the size 48×48.
2. Now we add a transparent border to this image. As a result the size would now be 50×50.
3. Next we use a pencil/pen tool with size 1 pixel, select the color as black and mark along the top and left borders to specify the area that we want to scale. You should end up with an image similar to the one shown above.
4. Finally specify the fill area by marking along the right and bottom borders.

Scalable Areas

Here are a couple of examples demonstrating how different scalable areas result in different types of scaling.

Single section that stretches in both directions

Single section that stretches in both directions

In the example below you will notice that, we have marked multiple patches on both left and top borders. As a result we now have 9 static areas, 12 partial stretchable areas and 4 complete stretchable areas. This helps us in cases where we don’t want certain parts of the images to be scaled. You can see how the red dot has remained uniform, no matter how it is scaled. In the previous case, the red dot was getting scaled along with the image size.

Multiple sections that stretch in both directions

Multiple sections that stretch in both directions

Fill areas or Padding

The purple section specifies the content area

The purple section specifies the content area

We now look into the area which the Android docs say is optional, though doesn’t clearly mention what the side effects would be. The Fill area can be specified by drawing black lines along the right and bottom borders. The content is restricted within the area specified by these lines. In the adjacent image, the area marked by the intersection of the left and right lines will be the content area of the View whose background is set with this 9-patch image.

The docs say that if these “optional” lines are not specified, then Android uses the top and left lines to define the fill area. Can you imagine how catastrophic the result would be in one of the example above? Well fortunately there is a way to deal with such cases but unfortunately it is not mentioned in the docs. You can see the “For the developers” section below for cases where the padding lines are not provided.

Points to Remember

Now that you know what 9-patch images are and how they are made, here are a few points you must keep in mind before you start.

  • 9-patch images can scale up but not scale down. Scaling down results in visual artifacts.
  • Always design for the smallest size possible. This will increase its re-usability.
  • If the Fill Area is not specified, then Android uses the top and left lines to define it. This may lead to visual artifacts.

For the Designers

  • The transparent border MUST be absolutely transparent and the border lines MUST be absolutely black ie #000000.
  • While resizing 9-patch images, remove the border, re-size it and then add the border. If you use an image editor to create and resize 9-patch, then antialiasing can ruin your image.
  • Android prefers that the ‘intersection zones’ are 1×1 pixel size for proper scaling. For bigger zones, the scaling could lead to visual artifacts.

For the Developers

  • If the Fill Area is not specified, there maybe abnormal behavior. In such cases, always specify some padding. And if you don’t require padding then use “padding=0dp”.
  • Put your 9-patch image in the /res/drawable folder to use for different densities and screen sizes and make sure they have “.9.png” extension.
  • If you are using the same 9-patch for different densities, then be cautious. The static areas will appear different based on the density. Make sure you check them on real devices and then decide if you require separate images for separate densities.
  • Do not use a 9-patch image that is bigger than your View.

Android ViewTree and DecorView

The Graphical User Interface forms an integral part of the Android application development. The UI not only acts as a mode of input for the user but also as a mode of feedback from the application based upon an action performed. It is therefore very important that a developer understands how the UI is created and updated.

ViewTree

The basic components of the visual UI is the View and a container called ViewGroup which contains a collection of Views. The ViewGroup itself is an extension of a View. The different widgets like the TextView, Button, etc are nothing but extensions of View which are all arranged within layouts, viz. LinearLayout, RelativeLayout. The layouts are nothing but sub classes of ViewGroup. A ViewTree is nothing but the tree structure that is formed as a collection of these views and viewgroups in a layout.

Let’s start with an example. Here you can see that a number of Views and a LinearLayout are all contained within a RelativeLayout which acts as the parent ViewGroup. All of these come together to form the ViewTree.

The tree structure as seen in Eclipse

When you set the view in your activity using setContentView() and run the program, you’ll see something like this.

If you see the xml file and the way each of the views have been drawn, you’ll observe the following.

  1. The ViewTree that is formed is traversed in a top-down fashion.
  2. The parent is always drawn first and then the children, again in a top-down fashion.

So in our example, the RelativeLayout Layout is first drawn, followed by its children WhiteView, RedText and so on, till finally GrayView is drawn obscuring the Views drawn before.

To visualize, how all the views are being drawn, think of the screen as a coordinate system consisting of X, Y and Z axes and the top-left of the screen as [0,0,0]. X extends to the right, while positive Y extends along the length of the screen. Z extends out of the screen. However do not confuse this system with the coordinate system of the Sensors of the phone.

The View Layout structure and their z-order

So the Views are basically placed along the positive Z axis as we move down the tree. Note that the Android drawing mechanism takes care that it does not draw parts of Views which are hidden by Views placed with greater z-values.

Now that we know how the Views defined by us in the xml are drawn, let us see if this all that there is in the View Tree. For this, we need the help of a tool known as the “heirarchyviewer” in the android installation folder under android-sdk/tools. Before we can use this tool, first run the program in the emulator or the device. Use the commandline to navigate to the folder and start the heirarchyviewer.bat file.

Shown below is the snapshot of the hierarchy viewer.

In the hierarchy viewer, the columns represent the depth of the tree while the number of rows in each column represents the breadth at each level. So you will notice that our RelativeLayout is not really at the root level but is in fact a child of a FrameLayout called “content”. The call to the setContentView(View v) basically sets the View v as the content view.

TreeView heirarchy of an Activity with a TitleBar

Now notice the column containing the FrameLayout “content”. It has a sibling which is another FrameLayout containing a TextView. This is nothing but the Title Bar of the Activity. Let’s see how the View Tree changes if we the titlebar is removed. Go to the manifest file and add the following line to thetag

android:theme="@android:style/Theme.NoTitleBar"

On running the hierarchy viewer, you will notice that the structure has changed. The content view now has just the “content” FrameLayout whose parent is the PhoneWindow$DecorView.

TreeView of the Activity without the TitleBar

Let us take a look at the PhoneWindow and the DecorView.

DecorView

PhoneWindow is the only implementation of the abstract “Window” class which provides the policies defining the look and feel of a window. It forms the top-level window which together with the WindowManager helps in setting the background, title area (either with TitleBar, ActionBar or a user specific custom title bar) and default key processing. The overall window properties can be customized using the WindowManager.LayoutParams.

The DecorView is a private class of the PhoneWindow which is nothing but an extension of FrameLayout. This is the class which forms the top-level application view. Based upon the settings provided in the Android Manifest regarding the themes or the flags set in the PhoneWindow on what type of a window we need to create, the layout of the DecorView is created. So for our example, in the first case, we had a simple theme containing containing a title bar and the contentview. The Phone Window generates a layout that consists of a linearlayout with the title and a framelayout where the contentview can be set. In the second case, we specified that we did not need a titlebar and hence it created the decorview with just the framelayout where the contentview can be set.

Conclusion

So here’s a brief of how the View Tree is generated when a Activity is started,

  1. The PhoneWindow generates a layout for the DecorView which forms the root view based upon the theme provided in the manifest file or otherwise specified using the Window interface.
  2. The activity’s setContentView() is used to set the layout xml as the content view. This internally calls the PhoneWindow’s setContentView().
  3. Now everytime the UI is refreshed the View Tree is traversed as mentioned earlier.

Note: If you plan to use a custom title bar using FEATURE_CUSTOM_TITLE, note that calling setContentView() for the first time or getDecorView() fixes your decorview and you can no longer change many window characteristics. Keep this in mind while designing.

Custom Control – Extending Existing Views

Building on our previous example of how we can extend existing controls and customize them for our requirements, we improve the “CustomFontTextView”. In the last post, we saw that by extending a TextView and then setting it’s font in it’s constructor we can achieve a TextView with custom fonts. But you will soon see that it rather restricts our development. If we were dealing with a number of different fonts, we would have to replicate them in multiple classes and then use each of them.

What we need is a more generic approach to the problem. As a developer, one should always build his own toolkit of reusable components over time which speeds up development. We could make it more generic if there was a way in which we could specify the font type at the time of defining the xml. This is possible by declaring an attribute through styleable which could be accessed through the xml.

So the basic steps are as follows

  1. Declare an attribute in a styleable which will be used to specify the font type.
  2. Add your custom fonts in the assets/fonts folder.
  3. Use the specified font type in the constructor of your extended TextView to access the custom fonts.

Let’s start with the styleable. In the “res/values” folder, we add a resource file called attrs.xml. This is the file where all our attributes of our custom controls go. In it we add the following piece of code.

[sourcecode language="xml"]
<?xml version="1.0" encoding="utf-8"?>
<resources>

<declare-styleable name="CustomFontTextView">
<attr name="fontName" format="enum">
<enum name="AirMole" value="0" />
<enum name="AirMoleAntique" value="1" />
<enum name="AirMoleShaded" value="2" />
<enum name="AirMoleStripe" value="3" />
</attr>
</declare-styleable>
</resources>
[/sourcecode]

We declare a styleable name “CustomFontTextView” and within it declare an attribute called “fontName” of type “enum”. In our example, we have four different font types which we have specified using name/value format.The attributes can be of different types such as integer, string, boolean, etc. We will discuss styleables in more details in another post.

The next thing we need to do is to access the attribute in our extended class. Check out the updated code of the CustomFontTextView below.

[sourcecode language="java"]
public class CustomFontTextView extends TextView {

public CustomFontTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if( !isInEditMode() ){
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomFontTextView,
defStyle, 0);

int fontId = a.getInteger(R.styleable.CustomFontTextView_fontName, -1);
if( fontId == -1 ){
throw new IllegalArgumentException("The font_name attribute is required and must refer "
+ "to a valid child.");
}
a.recycle();
initialize(fontId);
}

}

public CustomFontTextView(Context context, AttributeSet attrs) {
//call the constructor which has the complete definition
this(context, attrs, 0);
}

public CustomFontTextView(Context context) {
super(context);
//This fallbacks to the default TextView without applying any custom fonts
}

public void initialize(int fontId){

Typeface tf = null;
switch(fontId){
case 0:
tf = Typeface.createFromAsset(getContext().getAssets(), "fonts/airmole.ttf");
break;
case 1:
tf = Typeface.createFromAsset(getContext().getAssets(), "fonts/AirmoleAntique.ttf");
break;
case 2:
tf = Typeface.createFromAsset(getContext().getAssets(), "fonts/AirmoleShaded.ttf");
break;
case 3:
tf = Typeface.createFromAsset(getContext().getAssets(), "fonts/AirmoleStripe.ttf");
break;
}

setTypeface(tf);
}
}
[/sourcecode]

We declare a TypedArray which points to an array of values retrieved with obtainStyledAttributes(). We will look into it in more details at a later time. For now, we need to extract the fontName using the getInteger() of the TypedArray. We also pass a default value (-1 here) which is returned in case we don’t find a valid value in the array.

Note that it is important to call recycle() on the TypedArray so that the array can be cached for later use. A lot of people ask about the purpose of recycle() and why it is recommended. If you look at the code of TypedArray, you will realize that it is basically a caching mechanism which stores the currently retreived StyledAttributes for later re-use.

Once we retreive the fontId which is nothing but an enum value for the font name, we load the appropriate font type.

Finally, we need to use this in our xml files and specify the font. The code below does just that

[sourcecode language="xml"]
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.iwannalearn.customcontrols"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >

<com.iwannalearn.customcontrols.CustomFontTextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
app:fontName="AirMole"
android:text="AirMole" android:textSize="22sp"/>

<com.iwannalearn.customcontrols.CustomFontTextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
app:fontName="AirMoleStripe"
android:text="AirMoleStripe" android:textSize="22sp"/>

</LinearLayout>
[/sourcecode]

The implementation is pretty straight forward. You need to add the xml namespace of your custom control.

[sourcecode language="xml"]
xmlns:app="http://schemas.android.com/apk/res/com.iwannalearn.customcontrols"
[/sourcecode]

where “app” is the name we have assigned here to represent the namespace.

It can either be added at the top level viewgroup affecting the complete xml or just within your custom control. To specify the CustomFontTextView, you must specify the complete qualifying name. In this example, it is com.iwannalearn.customcontrols. CustomFontTextView. See what happens when you just specify CustomFontTextView. Check out the error that occurs.

To specify the font name, you must use the namespace:attributeName format. Ex, app:fontName = “AirMole”.

And that’s it! You are done. Compile and run it. If you have done things correctly you will see a screen similar to the following, with fonts specified by you.

Custom Fonts ScreenShot

Note: If you want to make it more generic. You could use a “string” format instead of “enum” and pass the name of the font to the CustomFontTextView. You can then use this name to open the appropriate file. Another thing that you can do to make it more efficient, is to create a spearate file which inflates the font file from the assets folder and keeps a reference to it. In that case, you can save re-inflation time, specially if you are using the CustomFontTextView in numerous places in your application.

You can view and download the complete working code here.

Custom Controls – An Introduction

Introduction

Very often while developing for Android, you will come across situations where you need a control which is not readily available in the default set of Android controls. However, Android was developed keeping the developer in mind, so that the developer’s creativity is not inhibited by the platform. All you need to do is just find out what and how to do.

There are a number of approaches which you can take to make a custom control, the choice however will depend on what you want and its level of complexity. The general approaches that you can take are as follows,

  1. Extend an existing View type or a widget. Pretty simple job here. Check if you have some existing View in the framework, extend it, implement the extra functions you require and you are done.
  2. Extend an existing ViewGroup (any layout) and put the controls you require in it. Add the extra functionalities and you are ready to reuse it in other places.
  3. Extend the class View/ViewGroup and implement everything. This is a little advanced and you would require a little extra knowledge of the way Android draws and creates layouts but this is the father of all customizations. With this method you can make a control that is as unique as you.
  4. Implement extra interfaces to existing Views/ViewGroups such that it can handle more events and do more. This is similar to 1 and 2, with the exception of implementing interfaces.
  5. Reuse the Google code of an existing widget and change its behavior. This might sound like a hack but you have to agree that there are times where you have looked at a control and thought, “if only…”. Eg, If only I could interchange the position of the RadioButton and its text. In some cases, it can be done by extending it but at other times, the behavior is so in its core that you need to reimplement it. At such times, its better to reuse the code than reinvent the wheel. There are 2 positives in this.
    • You see some really good code and learn from it.
    • Once you learn to figure out the way google writes code, you can quickly change it and come up with just the right control in quarter of a time.

I’ll be covering each of the cases, in following posts but for now, here’s a small introduction into how custom controls can make your life easier.

First Custom Control

When I first came across the requirement of setting fonts to my Textviews I was shocked to see that I could not set it through xml. The only fonts you can set using xml are the default android fonts. I knew how to go about it programatically but can you imagine the pain of setting it for every TextView in every file in the project?

The most natural thing to do was to extend the TextView and set the font in the constructor.And that is simple.

First, make a folder called “fonts” in the assets folder and put your font in it. In the example I have put the airmole.ttf file.

Next, extend TextView and in it’s constructor load the font and set it using setTypeface() and you are done.

[sourcecode language="java"]
public class CustomFontTextView extends TextView {

public CustomFontTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initialize();
}

public CustomFontTextView(Context context, AttributeSet attrs) {
super(context, attrs);
initialize();
}

public CustomFontTextView(Context context) {
super(context);
initialize();
}

public void initialize(){
if( !isInEditMode() ){
Typeface tf = Typeface.createFromAsset(getContext().getAssets(), "fonts/airmole.ttf");
setTypeface(tf);
}
}
}
[/sourcecode]

If you are wondering what the isInEditMode() does, then just comment the check and observe what happens to your graphical view of the xml in Eclipse. You will mostly see the following error,
The graphics preview in the layout editor may not be accurate: Typeface.createFromAsset() is not supported.

What the check basically does is that it avoids the code within it when you are viewing your xml and hence falls back to the default TextView. This helps in designing as you can actually see the content of the TextView.

Here is the xml file where the CustomFontTextView has been used.
[sourcecode language="xml"]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >

<com.iwannalearn.customcontrols.CustomFontTextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" android:textSize="22sp"/>

</LinearLayout>
[/sourcecode]

Note that the CustomFontTextView requires it’s complete qualifying name. Just specifying CustomFontTextView> will not work.