Pages

Friday, October 7, 2016

Android Studio 9-Patch Images

| Intro |

Developing my new App which targets Android platform and currently has a codename MyPlaceApp (I'm pondering about changing it to something more cool) I have encountered a lot of different issues and some of them were not so easy resolvable. Obviously, due to time constraints I won't discuss every solution I used in my project in this blog post. Today I'm gonna talk about an amazing way of preparing and integrating with Android Studio a bunch of the raster images that can be resized during runtime preserving the original quality.

Image scaling

This is a common task during mobile development to scale the image resources for the different screen sizes/densities regardless of the platform (Android or iOS). There are several techniques with the help of which we can obtain the required scaling. In particular, Android Developer Portal recommend us to use the following options:
  • Save the resized .png images into folders which define the abstract generalised screen densities: ldpi, mdpi, hdpi, xhdpi etc. By following this link you can check matching between the popular devices and the screen density groups. Android system automatically detects the current screen properties and loads the resources from the proper folders;
  • Import vector drawable into app/src/main/res/drawable/ folder. In this case images will be automatically resized without degrading the quality.

    Note: Android Support Library since version 23.2 provides support of vector drawables for the older API levels.

  • Draw custom shapes which can be defined in XML (e.g., res/drawable/filename.xml) with the specified colours or gradients.

Every option has its own pros and cons. Providing an image for each possible screen density can be very time consuming. At the same time, as the docs state
the initial loading of a vector drawable can cost more CPU cycles than the corresponding raster image
As per my case, I needed to find the solution that would allow me to use the raster images and, on the other hand, resize them without quality loss at the runtime (in accordance with the text content). At the first glance, this seems like magic. But finally I've found such solution. And it is called 9-Patch Images.

9-Patch Images

Here is the step-by-step instruction on how you can create and use the 9-Patch Images in your Android Studio projects:
  1. Using your favourite graphic editor create an image you want to use in your project. Here is what I got with the help of Affinity Designer:

  2. Background image created in Affinity Designer

    Since this is a vector editing program the image can be easily resized to .png with any resolution. But keep in mind that 9-Patch Images can be only stretched (not shrunk) so you should start with the smallest version of your icon.

  3. When you have the image ready copy it to the specific drawable folder. For example, this can be app/src/main/res/drawable-mdpi/.

    Note: For best results you should repeat this process for each screen density (xhdpi, xxhdpi etc.).

    Now right click the imported .png file in Android Studio and choose "Create 9-Patch File" option. You should see the open built-in 9-Patch editor like in the image below:

    Image in the built-in 9-Patch editor

  4. And now the most important part. To make it possible to scale this image while preserving the good quality you must draw 1px width black lines which would define the stretchable areas. The editor should already have added the 1px space around each image side. The topmost and leftmost lines specify the part of the original image that must be stretched when needed. Feel free to divide this line into multiple segments if you want to prevent scaling some specific elements (e.g., rounded corners) to save image quality. During the stretching process the Android platform just repeats the same colour pixels so the complex image parts must be excluded from this with the help of the aforementioned black lines.The right and bottom 1px black lines define the content area. For instance, if you have some dynamically generated text these lines would specify the exact rectangle where this text should be placed. If it cannot fit the defined area the image will be stretched in accordance with the specified stretchable parts.

    Let's look closer at the options which the built-in editor propose us:

    9-Patch editor with all checkbox selected

    Show lock - If this is selected on mouse hovering you will see the whole image covered by the diagonal red lines and only the 1px width lines on each side will remain transparent. This is just a reminder of where you are allowed to draw the meta black lines.

    Show patches - This option allows you to see the stretchable areas of your image. The green regions define the patches that will stretch either horizontal or vertical (not both). The pink define the fully stretchable patch.

    Show content - Shows the rectangle area where the content will be placed above the image.

    Show bad patches - This is the interesting one. When it is selected the problem parts of the image will be highlighted with the red rectangles. The term "problem parts" in this case means such image segments that can be distorted during scaling. As I said earlier, Android just repeats the same pixels when stretching the 9-Patch image. So if you have defined such stretchable areas where the adjacent pixels are different (even a little bit) the 9-Patch will doughtily report you that it is something wrong with your current image configuration. To ensure that the image will look good in all possible scenarios just select the stretchable areas where all the adjacent pixels are the same (have the same colour).


Basically, that's it. If you want to simplify the process of creating multiple 9-Patch images check out this nice third-party tool - Nine-patch Generator.

Hope this info will help someone.

No comments :

Post a Comment