Underlining views with custom shapes, overdraw performance

After the post of underlining views and custom drawables in android some people ask me about performance. So let’s talk about it.

So after a little research about performance I found this post http://www.curious-creature.org/2012/12/01/android-performance-case-study/ talking about performance and overdraw. I recommend read the post, but in resume we refer to overdraw as the number of times the GPU has to draw the screen for each component. You can active it in the Developer options as Show GPU overdraw.

It will color your screen this way:

Wordpress overdraw

  • No color means there is no overdraw. The pixel was painted only once. In this example, you can see that the background is intact.
  • Blue indicates an overdraw of 1x. The pixel was painted twice. Large blue areas are acceptable (if the entire window is blue, you can get rid of one layer.)
  • Green indicates an overdraw of 2x. The pixel was painted three times. Medium-sized green areas are acceptable but you should try to optimize them away.
  • Light red indicates an overdraw of 3x. The pixel was painted four times. Small light red areas are acceptable.
  • Dark red indicates an overdraw of 4x or more. The pixel was painted 5 times or more. This is wrong. Fix it.

In the other post we put this drawable:

Layers 2

<?xml version="1.0" encoding="utf-8"?>

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true">
        <layer-list>
            <item>
                <shape>
                    <solid android:color="#ffff7a00" />
                </shape>
            </item>
            <item android:bottom="3dp">
                <shape>
                    <solid android:color="#222222" />
                </shape>
            </item>
        </layer-list>
    </item>
</selector>

And we can see it has a 2x overdraw (green color) because of the 2 layers:

2 x overdraw

But we can fix that by changing the drawable for not to overlap between the layers.

layers_no_overlap_1

<?xml version="1.0" encoding="utf-8"?>

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true">
        <layer-list>
            <item android:bottom="3dp">
                <shape>
                    <solid android:color="#222222" />
                </shape>
            </item>
            <item android:top="29dp">
                <shape >
                    <solid android:color="#ffff7a00" />
                </shape>
            </item>
        </layer-list>
    </item>
</selector>

Now we have a 1x (blue) overdraw:

1 Overdraw

Because now the layers do not overlap it doesn’t matter which layer goes on top of another.

The main drawback of this method is that you only can use if you know beforehand the height of the drawable.

If you don’t know the height you will have to use a 9patch button or keep it like we put in the previous post paying the overdraw cost.

In our case we would use the drawable method in development to be able to change the drawables fast, and change to 9patch button if needed.

Example with 3 layer

This drawable is compound of 3 layers (see this post if you want to see the xml).

3 Layers example

The overdraw of this view is 3x:

3xoverdraw

Changing the drawable we can reduce it to a 1x factor:

Layers no overlap 2

<item android:state_selected="true">
    <layer-list>
        <item android:top="29dp">
            <shape>
                <solid android:color="#222222" />
            </shape>

        </item>
        <item android:top="26dp" android:bottom="3dp">
            <shape >

                <solid android:color="#ffff7a00" />
            </shape>
        </item>
        <item android:bottom="6dp">
            <shape>
                <solid android:color="#222222" />
            </shape>
        </item>
    </layer-list>
</item>

With the new xml the overdraw remains 1x (blue).

New overdraw for 3 layers

Underlining views, custom drawables in android

Edit:
In this post we talk about the performance of this method.

Sometimes we want to underline a view (a TextView or a Button), just to show the user that it’s active, or any other reason.

To achieve this we use custom drawables. In this case we use a layer-list.

The first element of the layer list is the base, and every item we put it’s a layer that goes on top, let’s try with an image, and it corresponding xml:

Layers

And here is the drawable. We can see that the first element is the base layer:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <layer-list>
            <item>
                <!-- layer 1-->
            </item>
            <item>
                <!-- layer 2-->
            </item>
            <item>
                <!-- layer 3-->
            </item>
            <item>
                <!-- layer 4-->
            </item>
        </layer-list>
    </item>
</selector>

And now to achieve the effect we must know the bottom, top, right and left properties of item. They are similar to the margin property, but the are relative to the view.

So if we set the bottom of the second layer to 3dp (for example) we will be able to see 3dp of the layer below in the bottom. Here is an example:

Layers 2

<?xml version="1.0" encoding="utf-8"?>

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true">
        <layer-list>
            <item>
                <shape>
                    <solid android:color="#ffff7a00" />
                </shape>
            </item>
            <item android:bottom="3dp">
                <shape>
                    <solid android:color="#222222" />
                </shape>
            </item>
        </layer-list>
    </item>
</selector>

Now we only need to assign the drawable to the background property of our view (ImageView, Button, etc).

Here is how it came out in my app:

Bar

Other effects

We can put lines in top and bottom at the same time:

Top and bottom

<?xml version="1.0" encoding="utf-8"?>

<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_selected="true">
        <layer-list>
            <item>
                <shape>
                    <solid android:color="#ffff7a00" />
                </shape>
            </item>
            <item android:top="3dp" android:bottom="3dp">
                <shape>
                    <solid android:color="#222222" />
                </shape>
            </item>
        </layer-list>
    </item>
</selector>

We can also put a line in one (or both) sides. Here we have a line in the left.

Left

<?xml version="1.0" encoding="utf-8"?>

<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_selected="true">
        <layer-list>
            <item>
                <shape >

                    <solid android:color="#ffff7a00" />
                </shape>
            </item>
            <item android:left="3dp">
                <shape>
                    <solid android:color="#222222" />
                </shape>
            </item>
        </layer-list>
    </item>
</selector>

We can use more that 2 layers to achieve new effects. Here we use 3 layers to get this effect.

Explaining 3 layers
3 Layers example

<?xml version="1.0" encoding="utf-8"?>

<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_selected="true">
        <layer-list>
            <item >
                <shape>
                    <solid android:color="#222222" />
                </shape>

            </item>
            <item android:bottom="3dp">
                <shape >

                    <solid android:color="#ffff7a00" />
                </shape>
            </item>
            <item android:bottom="6dp">
                <shape>
                    <solid android:color="#222222" />
                </shape>
            </item>
        </layer-list>
    </item>
</selector>

Using “animation layers” to build complex bitmaps animations in Android

For the android game WhoSaid we wanted to animate a character reading (we call it will). But we wanted it to appear completely random.

will

We wanted the character to move the eyebrows, the eyes and the mouth separately. But the number of combinations were too high (120 frames), making almost impossible not to crash the app, and complicating the xml for the animation.

So we decided to divide the character into three “animation layers”: body + eyebrows (3 frames), eyes (5 frames) and mouth (8 frames). 16 frames in total, but this way we have 120 combinations.

Layout configuration

So we figured out who to do it minimizing the number of images. We used a FrameLayout as container of the layers. And each animation layer is an ImageView.

In the layout file we must include a FrameLayout where we are going to put the ImageViews. In this case we have three ImageViews, one for the eyebrows animation , other for the eyes animation and the last for the mouth animation.

The order of the ImageViews is important. The first ImageView is the base, and the later views are in top of that in descending order. In this case the base goes first, and later the eyes view.

Here is the layout file:

<?xml version="1.0" encoding="utf-8"?>

<!--Container of the three layers-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:padding="10dp">

    <!--First layer -> Base layer-->
    <ImageView
        android:layout_gravity="center"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/willBase"
        android:src="@drawable/will_transparent" />

    <!--Second layer-->
    <ImageView
        android:layout_gravity="center"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/willEyes"
        android:src="@drawable/will_transparent" />

    <!--Third layer -> Top layer-->
    <ImageView
        android:layout_gravity="center"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/willMouth"
        android:src="@drawable/will_transparent" />
</FrameLayout>

Don’t forget to set the src property of your ImageViews to a transparent bitmap of the same size of your frames. If not the images of the animation will stretch to occupy all the view without maintaining proportions.

Drawable configuration

First of all, all the frames must be the same size.

Frame sizes must be equals.

Frame sizes must be equals.

And now the configuration for the three layers.

First layer (base layer)

Here we have the tree images that compound our base animation layer.

Eyebrows animation.

Base image with the three frames that compose the eyebrows animation.

With this three images we create an animation drawable:

<?xml version="1.0" encoding="utf-8"?>

<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">

    <item android:drawable="@drawable/base_eyebrows_no_mouth_001" android:duration="4350"/>
    <item android:drawable="@drawable/base_eyebrows_no_mouth_002" android:duration="4375"/>
    <item android:drawable="@drawable/base_eyebrows_no_mouth_003" android:duration="4250"/>

</animation-list>

Second layer, eyes animation

And in top of that we will set our eyes animation, composed by five frames.

Frames that compose the eyes animation.

Frames that compose the eyes animation.

And the xml for this animation:

<?xml version="1.0" encoding="utf-8"?>

<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
    <item android:drawable="@drawable/will_eyes_001" android:duration="810"/>
    <item android:drawable="@drawable/will_eyes_002" android:duration="810"/>
    <item android:drawable="@drawable/will_eyes_003" android:duration="810"/>
    <item android:drawable="@drawable/will_eyes_001" android:duration="910"/>
    <item android:drawable="@drawable/will_eyes_002" android:duration="910"/>
    <item android:drawable="@drawable/will_eyes_003" android:duration="810"/>
    <item android:drawable="@drawable/will_eyes_004" android:duration="50"/>
    <item android:drawable="@drawable/will_eyes_005" android:duration="50"/>

</animation-list>

Third layer, mouth

Frames that compound the mouth animation. I show you as a gif because there are 8 frames.

Mouth animation

And here we have the animation xml:

<?xml version="1.0" encoding="utf-8"?>

<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="true">

    <item android:drawable="@drawable/will_mouth_001" android:duration="225"/>
    <item android:drawable="@drawable/will_mouth_008" android:duration="275"/>
    <item android:drawable="@drawable/will_mouth_004" android:duration="250"/>
    <item android:drawable="@drawable/will_mouth_006" android:duration="225"/>
    <item android:drawable="@drawable/will_mouth_002" android:duration="250"/>
    <item android:drawable="@drawable/will_mouth_006" android:duration="275"/>
    <item android:drawable="@drawable/will_mouth_007" android:duration="250"/>
    <item android:drawable="@drawable/will_mouth_003" android:duration="300"/>
    <item android:drawable="@drawable/will_mouth_004" android:duration="250"/>
    <item android:drawable="@drawable/will_mouth_008" android:duration="350"/>
    <item android:drawable="@drawable/will_mouth_004" android:duration="225"/>
    <item android:drawable="@drawable/will_mouth_003" android:duration="250"/>
    <item android:drawable="@drawable/will_mouth_006" android:duration="280"/>
    <item android:drawable="@drawable/will_mouth_007" android:duration="300"/>
    <item android:drawable="@drawable/will_mouth_003" android:duration="275"/>
    <item android:drawable="@drawable/will_mouth_008" android:duration="375"/>
    <item android:drawable="@drawable/will_mouth_002" android:duration="250"/>
    <item android:drawable="@drawable/will_mouth_007" android:duration="350"/>
    <item android:drawable="@drawable/will_mouth_006" android:duration="250"/>
    <item android:drawable="@drawable/will_mouth_003" android:duration="240"/>
    <item android:drawable="@drawable/will_mouth_001" android:duration="225"/>

</animation-list>

You will notice that there are repeated drawables. That not increase the memory that the animation occupy, but it gives a more variety animation.

Code configuration

And last but not least we have to code our animation.

private void animateWill() {
    ImageView willBase = (ImageView) getView().findViewById(R.id.willBase);
    willBase.setAdjustViewBounds(true);
    willBase.setBackgroundResource(R.drawable.will_base_eyebrows_animation);
    AnimationDrawable eyebrowsAnimation =(AnimationDrawable) willBase.getBackground();
    eyebrowsAnimation.start();

    ImageView willEyes = (ImageView) getView().findViewById(R.id.willEyes);
    willEyes.setAdjustViewBounds(true);
    willEyes.setBackgroundResource(R.drawable.will_eyes_animation);
    AnimationDrawable readingAnimation =(AnimationDrawable) willEyes.getBackground();
    readingAnimation.start();

    ImageView willMouth = (ImageView) getView().findViewById(R.id.willMouth);
    willMouth.setAdjustViewBounds(true);
    willMouth.setBackgroundResource(R.drawable.will_mouth_animation);
    AnimationDrawable mouthAnimation =(AnimationDrawable) willMouth.getBackground();
    mouthAnimation.start();
}

Basically you have to find the view, set the background resource, prepare the animation and start it.

Memory problems

If you are careless it’s easy to run out of memory using this method, cause you are working with lots of bitmaps. It’s strongly recommend to use custom drawables for each pixel density. Each pixel counts especially on low-level devices.

Be careful with Roboguice and creating and destroying Activities/Fragments that has animations.  When finishing an Activity/Fragment that extends a RoboActivity/RoboFragment it’s not destroyed immediately, it has to wait for a Finalizer to be garbage collected. It will occur but It will not fast, even if you call the garbage collector. So if you create a lot of views you will face a problem.

For this game we only used Roboguice to inject views, so we decided to implement the view injection by ourselves in some kind of framework we are building for future applications (that function it’s very few code indeed). We will release it soon, when it is a little bit more mature.

Managing ImageButtons

Sometimes when designing our application we limit the touch area of a ImageButton to its image, making the buttons difficult to use and our users angry.

Or for the contrary, we make the ImageButton bigger distorting the image in the process.

This is because we are managing bad the src and background properties of ImageButton.
The key is to assign the image to the src property, not the background.
If you set the image to the background it will stretch until occupy all the button.
Don’t forget to set the background to null (@null) or transparent (@android:color/transparent) or the background will get a light gray touch.

Bad
The image is set to the background property, and the image get stretched:

Stretched button

<ImageButton
    android:id="@+id/brush"
    android:layout_height="fill_parent"
    android:layout_width="0dp"
    android:layout_weight="1"
    android:layout_height="fill_parent"
    android:background="@drawable/ic_action_edit"/>

Bad
There background is not set to transparent and we get a gray background.

Light background

<ImageButton
    android:id="@+id/brush"
    android:layout_height="fill_parent"
    android:layout_width="0dp"
    android:layout_weight="1"
    android:layout_height="fill_parent"
    android:src="@drawable/ic_action_edit"/>

Good

Good

<ImageButton
    android:id="@+id/brush"
    android:layout_height="fill_parent"
    android:layout_width="0dp"
    android:layout_weight="1"
    android:src="@drawable/ic_action_edit"
    android:background="@null"/>

It has the layout_width to 0dp and the weight to 1 because it is in a LinearLayout occupying all the width. Here is the result.

Bar

Better
Finally, to give the user a feedback I create a drawable (called background_button)that highlights the button when is pressed.

Pressed button

<ImageButton
    android:id="@+id/brush"
    android:layout_height="fill_parent"
    android:layout_width="0dp"
    android:layout_weight="1"
    android:src="@drawable/ic_action_edit"
    android:background="@drawable/background_button" />

Here is the drawable:

<?xml version="1.0" encoding="utf-8"?>

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <shape android:shape="rectangle">
            <solid android:color="#44ffffff" />
            <corners android:bottomLeftRadius="6dp" android:bottomRightRadius="6dp" android:topLeftRadius="6dp" android:topRightRadius="7dp" />
        </shape>
    </item>
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#00ffffff" />
            <corners android:bottomLeftRadius="6dp" android:bottomRightRadius="6dp" android:topLeftRadius="6dp" android:topRightRadius="6dp" />
        </shape>
    </item>
</selector>

 

Custom fonts in TextView and FontCache

Lot of times we want to  use a custom font in a TextView. One way to achieve this is to create our custom class that extends TextView.

First we place our fonts in the Asset folder. In this case we are going to use the SEGOE font, and put the font under the fonts folder in the assets.

Then we create our custom class. I have place it under es.slothdevelopers.views. And I have call it SegoeTextView.

public class SegoeTextView extends TextView {

    public SegoeTextView(Context context) {
        super(context);
    }

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

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

    @Override
    public void setTypeface(Typeface tf, int style) {
        if (!this.isInEditMode()) {
            if (style == Typeface.NORMAL) {
                super.setTypeface(FontCache.getFont(getContext(), "fonts/SEGOEUI.TTF"));
            } else if (style == Typeface.ITALIC) {
                super.setTypeface(FontCache.getFont(getContext(), "fonts/SEGOEUII.TTF"));
            } else if (style == Typeface.BOLD) {
                super.setTypeface(FontCache.getFont(getContext(), "fonts/SEGOEUIB.TTF"));
            }
        }
    }
}

We have override the setTypeface method to be able to change the font between bold, italic and normal in the layout without having to create another custom class.

We also used a FontCache to load the typeface:

FontCache.getFont(getContext(), "fonts/SEGOEUI.TTF")

Instead of calling:

Typeface.createFromAsset(getContext().getAssets(), "fonts/SEGOEUI.TTF");

It’s a good practice to use a font cache, the performance is much better. This can be quite important in elements that are created lot of times, such a ListView or a GridView.

Here we have the code of our FontCache:

public class FontCache {
    private static Map<String, Typeface> fontMap = new HashMap<String, Typeface>();

    public static Typeface getFont(Context context, String fontName){
        if (fontMap.containsKey(fontName)){
            return fontMap.get(fontName);
        }
        else {
            Typeface tf = Typeface.createFromAsset(context.getAssets(), fontName);
            fontMap.put(fontName, tf);
            return tf;
        }
    }
}

Now to use this custom TextView we just have to change our layout. For example:

<es.slothdevelopers.views.SegoeTextView
                        android:id="@+id/date"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="Mar 18, 2014 a las 18:01"
                        android:textColor="@color/text_color"
                        android:textSize="12sp" />

In the layout we can change the textStyle and it will change in our app.
In this view I used the same view for the name that for the date. I only had to add: android:textStyle=”bold”.

Custom TextViews

Bubble Me, searching for an algorithm

BubbleMe was our first android application, we encounter many difficulties during it’s development.

Most of them related to memory leaks, image processing and the garbage collector. To find those memory leaks we had to use the Eclipse Memory Analizer and had to understand the inner of memory management in Android. This google IO conference was indispensable to achieve this goal. It may seem long (1 hour), but is worth it.

Image processing in android isn’t a pain in itself, but handling the images in a limited memory  is. If you are careless you will crash your app.

The algorithm

In Bubble Me we have one goal: simulate the effect of being nude through a pattern made of circles that only let us see the naked parts of a person. Here we have an example with Olivia Wilde:

Olivia Wilde Bubbled

 

Studying the effect on internet images we set some objectives to our algorithm:

  1. Hide all the clothes.
  2. The face must appear in the picture.
  3. The circles will never intersect; it will break the pattern.
  4. Maximize the area of the circles and it’s own size.

First approximation

The only points we had clear when we started were points 1 and 2. The other we will discover through time and many tries.

We need the user to provide where are the clothes. So we ask him to paint over.

We also need to know where are the faces so, again, we ask the user for that information. We tried to use facial recognition, but not always work.

Once we have this information we throw a big number of random points and check if it’s painted or not. If it isn’t painted we create a circle as big as possible in that location.

Later we arrange the obtained circles by size, and add the circles to the image being carefully that they don’t intersect.

Looking backwards it seem a little crazy and a waste of resources, but we need a start point.

Quadtree approximation

This image shows a quadtree of a line. From: http://cybertron.cg.tu-berlin.de/pdci11ws/gdi/

Quadtree analysis of a line

After some improvements on the previous algorithm we decided to try another approach. We decided to use QuadTrees.

Quadtrees are often use in 2D collisions (or 3D collisions if we are talking about 3D collisions), and are known for their great performance. So we supposed that would improve the generation time of the pattern. Also we discovered that the quadtree provided us very useful information to our purposes. The bigger areas were where we should place our circles.

To increase even more the cover area we slightly (and iteratively) moved the circles to maximize the occupied space.

The performance improvement was great, and we decided to stick to this algorithm.

Other algorithm: Delaunay triangulation  and Voronoi cells

 

Delaunay triangulation (black) and Vornoi cells (red)

Delaunay and Voronoi

Beside of using quadtrees for the algorithm we think there are event faster ways of creating the pattern.  Using Delanuay and Voronoi (they are correlated).

Finding the Delaunay triangulation it’s even faster than calculate the quadtree for the image. And the points of the triangulation would be the center of our circles in the pattern.

There are several implementations in the net of this algorithms, so that wouldn’t be a problem. Maybe the hardest part would be to represent the clothes as unwanted zones, and for that we keep the quadtree implementation.