Today's #AndroidDesign #Protip from +Roman Nurik is about aiming for fewer PNGs and more XML.

We review a lot of apps here on the Android Developer Relations team. As part of that review, sometimes we dig into APKs (particularly the manifest and resources) to see what goodies lie within. Now, we've seen everything from several megs of In-App billing documentation (yes, HTML, Javascript, the works) for wait for it—another platform (!!) sitting in the APK root all the way to hundreds of button images with blurry pre-baked text sitting in the density-disregarding res/drawable folder. 

The one thing we see too much of is loads of PNG files that don't need to be there. We've really got to start thinking carefully about alternative ways to deliver the same UI. And remember, the Holo visual language is all about letting spacing, typography and dynamic images do the work, rather than the often unnecessary static UI elements that churn down your data/pixel ratio [1].

With that, let's look at a couple common examples where PNGs in your app binary could be replaced with something else:

Simple shapes: If all you need is a simple shape, like a circle mask for a contact avatar, or a simple circular button, just use Android's shape XML drawables [2]. It's quick and easy. Here's an example: http://goo.gl/30ajpA

Gradients: Oftentimes you'll find yourself using black-to-transparent gradients for background protection of text on images. Shape XML works great for this as well. Here's an example of that: http://goo.gl/Adh1lz

Large nine-patches: First, if you haven't heard of nine-patches [3], stop what you're doing and go read about them immediately! Now, if your .9.png files have large stretch regions, see if you can shrink them. The PNG file format does a decent job optimizing repetition like this anyway, but not always. The Android Asset Studio's nine-patch generator [4] has a "trim" option that trims excess stretch regions. Be careful with very small (1px) regions though if you're relying on platform scaling to lower densities.

"Pressed" state button images: While it's critical that users see a visual change when pressing an interactive element such as a button, you can often save the trouble of creating additional PNGs just for this purpose. Layer list drawables [5] let you overlay several drawables on top of one another. If the bottom drawable is your default-state button PNG and the top is a state list drawable that's transparent by default and a semitransparent white/black when pressed, the effect will be that your default-state button is lightened/darkened on press. Here's an example from the I/O 2013 app: http://goo.gl/Xcx1nk

There are of course tons of other possible ways to remove PNGs, and these can often be combined. For example, sometimes you'll want to add a bit of noise over your gradients to minimize banding artifacts. That's simple: a layer-list drawable containing a gradient shape drawable and a <bitmap> [6] drawable referencing a small "noise" PNG tile with a tileMode set to repeat will do the trick.

To wrap up, I'd recommend the following exercise. Open up your APK (it's just a ZIP file!), or your project tree, and take a long hard look at the PNGs in your drawable directories. Can you replace any of them with XML drawables, or even custom drawing code? And better yet, do you even really need them in your UI, or are they unjustifiably lowering your data/pixel ratio?

Have similar tips and tricks? Leave 'em in the comments!

[1] Minimalist interface design and the data-pixel ratio https://medium.com/design-ux/49df9dcd997a
[2] Shape drawables http://goo.gl/QV5P
[3] Nine-patches http://goo.gl/zGxf4B
[4] Nine-patch generator http://goo.gl/QBjiX
[5] Layer list drawables http://goo.gl/SXqNlb
[6] Bitmap with tileMode http://goo.gl/sz3qVH
259
134
Adnan A M's profile photoTed Chien's profile photoRoman Nurik's profile photoYao-Te Tsai's profile photo
16 comments
 
Moar!
Watching real mistakes is one of the best ways to learn, and I'm sure people will be glad to see more of this.
Thanks! 
 
There would be even less PNG files if Android had a direct support for SVG files.
 
I wonder why platform has so much png files which could easily be replaced by xml drawables (e.g.  list selector)
 
Last time I took a look at the nine-patches tool and documentation it was horible. When talking about images in android there is one thing that pops up in my mind.
Why is there no default way to load images asynchronosly?

Btw.: I miss SVG support too.
 
Great article. Every android dev must to know that, and every designer must to know that as well
 
I don't understand the layer-list one. How does that reduce the number of drawables? You still need those different states anyway, don't you?
Or is that top layer just a color that is only non-transparent when pressed/active/whatever and you still only have one png for the actual button?
 
+Thomas Fiedler I think the problem is that sometime people include 4 pngs to represent 4 different states for a particular button when those state differences could be created simply by overlaying 1 button png with 3 different effects that you could create using an xml drawable.
 
I'm pretty sure I've seen the opposite argument as well, that is using PNGs over xml drawables. The argument being that xml drawables are more heavy on the CPU.

Is it the combination of higher DPIs (larger PNGs) and more being rendered by the GPU that changes the position here?
 
+Andreas Nilsson I  was under the same impression ! I replaced XML drawables from my app to 9patch images ! 
 
+Roman Nurik If any app want to support the dark and light theme, the menu icon on the action bar would requires 2 png each of dpi. Can It be reduced to XML?
 
+Roman Nurik What is your take on using fonts for icons, such as awesome font for web, as long as the follow the guideline in terms of icon graphics?
Add a comment...