Friday 17 February 2012

All about 9-patch image in android.

While I was working on my Android App I found 9-patch (aka 9.png) to be confusing and poorly documented. After a little while, I finally picked up on how it works and decided to throw together something to help others figure it out. As Android devices come in many shapes and sizes, often making it very difficult for developers to design applications that look great on all the various screen sizes and orientations. For addressing this challenge,9-patch  can be indispensable. In this article, I will discuss what the 9-patch graphics format is, how it works, and when to use it.
What is the 9-patch  !!! 
Android supports 9-patch Stretchable Graphics for the controlled scaling of images. 9-patch graphics uses .png transparency to do an advanced form of 9-slice or scale9  that have patches, or regions of the image, defined to scale and stretch in the appropriate areas instead of scaling the entire image as one unit, which often obscures the details of the graphic. Generally, the center patch is transparent or solid, With  parts of the edges set to remain fixed, other edge parts set to stretch, and the corners set to remain fixed.


Here’s a basic guide map:


As you can see, you have guides on each side of your image. The TOP and LEFT guides are for scaling your image (i.e. 9-slice), while the RIGHT and BOTTOM guides define the fill area.
The black guide lines are cut-off/removed from your image – they won’t show in the app.  Guides must only be one pixel wide, so if you want a 48×48 button, your png will actually be 50×50. Anything thicker than one pixel will remain part of your image. (My examples have 4-pixel wide guides for better visibility. They should really be only 1-pixel).
Your guides must be solid black (#000000). Even a slight difference in color (#000001) or alpha will cause it to fail and stretch normally. This failure won’t be obvious either*, it fails silently! Yes. Really. Now you know.
Also you should keep in mind that remaining area of the one-pixel outline must be completely transparent. This includes the four corners of the image – those should always be clear. This can be a bigger problem than you realize. For example, if you scale an image in Photoshop it will add anti-aliased pixels which may include almost-invisible pixels which will also cause it to fail*. If you must scale in Photoshop, use the Nearest Neighbor setting in the Resample Image pull down menu (at the bottom of the Image Size pop-up menu) to keep sharp edges on your guides. This is actually a “fix” in the latest dev kit. Previously it would manifest itself as all of your other images and resources suddenly breaking, not the actually broken 9-patch image.
The TOP and LEFT guides are used to define the scalable portion of your image – LEFT for scaling height, TOP for scaling width. Using a button image as an example, this means the button can stretch horizontally and vertically within the black portion and everything else, such as the corners, will remain the same size. This allows you to have buttons that can scale to any size and maintain a uniform look.
It’s important to note that 9-patch images don’t scale down – they only scale up. So it’s best to start as small as possible.
Also, you can leave out portions in the middle of the scale line. So for example, if you have a button with a sharp glossy edge across the middle, you can leave out a few pixels in the middle of the LEFT guide. The center horizontal axis of your image won’t scale, just the parts above and below it, so your sharp gloss won’t get anti-aliased or fuzzy.

Fill area guides are optional and provide a way define the area for stuff like your text label. Fill determines how much room there is within your image to place text, or an icon, or other things. 9-patch isn’t just for buttons; it works for background images as well.
The above button & label example is exaggerated simply to explain the idea of fill – the label isn’t completely accurate. To be honest, I haven’t experienced how Android does multi-line labels, but there’s a good explanation of how to do them on Stack Overflow. Usually, a button label is usually a single row of text.
Finally, here’s a good demonstration of how scale and fill guides can vary, such as a LinearLayout with a background image & fully rounded sides:
Creating 9-patch Graphics
Let's give it a try. I've created a really basic PNG file called bluenotstretchy.png. To create a NinePatch graphic from this PNG file using the Draw 9-patch tool, perform the following steps:
1.       Launch Draw 9-patch.bat in your Android SDK /tools directory.
2.       Drag the PNG file into the left-hand pane (or use File -> Open NinePatch…)
3.       Click the "Show Patches" checkbox at the bottom of the left pane.
4.       Set your Patch Scale appropriately (higher to see more obvious results).
5.       To set a horizontal patch guide, click along the right edge of your graphic.
6.       To set a vertical patch guide, click along the top edge of your graphic.
7.       View the results in the right pane, and move patch guides until the graphic stretches the way you intend it. 
8.       If you need to delete a patch guide, press Shift and click on the guide pixel (black).
9.       Save your graphic with the extension .9.png (e.g., blue.9.png).

Loading 9-patch Graphic Resources from java file :
9-patch resources are simply another kind of Drawable subclass called NinePatchDrawable. Most of the time, you'll need only the resource ID of the image, to set as an attribute of View or layout. Occasionally you might need to act on the resource programmetically.
To create a NinePatchDrawable object from a NinePatch drawable resource, use the resource'sgetDrawable() method. If the drawable is a NinePatch, the getDrawable() method will return a NinePatchDrawable instead of a generic BitmapDrawable object.
For example, to load a NinePatch drawable resource called blue.9.png, you could use the following code:
import android.graphics.drawable.NinePatchDrawable;
NinePatchDrawable myNinePatchDrawable = (NinePatchDrawable) getResources().getDrawable(R.drawable.blue);
You can then use the NinePatchDrawable object much as you would any BitmapDrawable.

Enjoy.... 
Do post your doubts, queries or suggestions in this blog.


1 comment:

  1. Hey..Thanks a lot...Its really a great article. I always face trouble while running my app on different screen size devices. But finally I got solution here. Thanks a lot again.

    ReplyDelete