Logo Icon Logo
A Crowd-sourced Cookbook on Writing Great Android® Apps
GitHub logo Twitter logo OReilly Book Cover Art

ImageButton State Graphics Using Inkscape

Author: Daniel Fowler -- Published? false -- FormatLanguage: W

Problem:

You need to add interest to a screen with custom buttons.

Solution:

Use the ImageButton, and design images in a graphics program, such as Inkscape, adding your own style to buttons in your App.

Discussion:

A good User Interface should be intuitive and attractive. Sometimes simple pictures can replace words, or many words on a screen. Symbols, colors and pictures can make a screen attractive and easy to use. The ImageButton is a useful View when designing screens. Out of the box it supports three visual states, normal, focused and pressed. Without a custom image the states are just plan colored rectangles, grey for normal, orange for focus, dark yellow for pressing. However it is easy to add a custom image for each of these states using a graphics program. This allows an ImageButton to be made unique. Inkscape ([1]) is a good program for producing graphics for the Android platform. Inkscape is:

  • Fully featured
  • Free
  • Supports multiple screen densities (vector based)
  • Access to thousands of free images via the Open Clip Art Library ([2])
  • Plenty of online tutorials.

Images can also be generated with programs such as GIMP, ([3]) or Paint.NET ([4]), but working with vector instead of raster images makes it easier to produce the variety of sizes needed for multiple screen densities.

Those that are not familiar with working in Inkscape can use the built in tutorials (under the Help menu) and tutorials at [5] to teach themselves.

This recipe uses an ImageButton to represent Play (or Start, or Go). The three images to be used can be built in Inkscape, or alternatively they are available from the Open Clip Art Library ([6]):

Image ImageButton State Project Name Open Clip Art Name Open Clip Art Search
normal normal.png Architetto -- pulsante 02 pulsante
focus focus.png Blue Play Button With Focus play button
pressed pressed.png Play Button Green With Blue Border play button

Use the Inkscape Export Bitmap dialog to generate the bitmaps of the required size (using the Width and Height boxes). These can be exported directly to the relevant drawable folder.

Ideally bitmaps will be generated for the various screen densities possible on Android devices. Medium density (160dpi) is the default density. Images placed in the drawable folder will be scaled for different density screens unless an equally named file is in the correct folder under the res folder: drawable-ldpi, drawable-mdpi (same as drawable), drawable-hdpi and drawable-xhdpi. The relative sizes are shown in the following diagram.

A bitmap that is 60x60 on a medium density screen would be 45x45 on a ldpi screen, 90x90 on a hdpi screen and 120x120 on a xhdpi screen. Bitmaps produced from Inkscape for the various densities will reduce the pixellation that can occur from scaling the default bitmap. In many cases no additional code will be required to support the different density screens.

If a suitable file is already in the Open Clip Art Library then a PNG file can be generated directly from that image's web page. Type the image size required into the box below the View Image button and click the PNG button. Use the browsers File menu to save the generated image to the correct directory, changing the file name if required.

Referencing an image from a View or Widget is usually achieved by setting an attribute to the name of the file in a drawable folder. However, an ImageButton needs three images, with the correct image required being based upon the button's state. This is achieved via an XML selector file in the drawable directory, the relevant attribute then points to this XML file. The following file can be used to reference the images generated above.

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_pressed="true"
           android:drawable="@drawable/pressed" />
     <item android:state_focused="true"
           android:drawable="@drawable/focus" />
     <item android:drawable="@drawable/normal" />
</selector>

It is important that the image for the normal state appears last in the selector file. Android tests the state of the button and if no image for the given state is in the list then the last image is used, which is for the normal state.

The layout below places two ImageButtons in a TableLayout, along with two TextViews for labels. Focus can be moved between the buttons using the trackball or joystick (or arrow keys).

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
<TableLayout android:layout_width="fill_parent"
    android:layout_height="wrap_content">
    <TableRow android:id="@+id/tableRow1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center">
    	<ImageButton android:id="@+id/button1"
    	    android:layout_width="wrap_content"
    	    android:layout_height="wrap_content"
    	    android:src="@drawable/state_images"
    	    android:background="@android:color/transparent"
    	    android:padding="5dp"/>
    	<TextView android:id="@+id/textview1"
    	    android:layout_width="wrap_content"
    	    android:layout_height="wrap_content"
    	    android:text="Press Me!"
    	    android:textSize="20dp"
    	    android:layout_gravity="center"/>
    </TableRow>
    <TableRow android:id="@+id/tableRow2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    	<ImageButton android:id="@+id/button2"
    	    android:layout_width="wrap_content"
    	    android:layout_height="wrap_content"
    	    android:src="@drawable/state_images"
    	    android:background="@android:color/transparent"
    	    android:padding="5dp"/>
        <TextView android:id="@+id/textview2"
    	    android:layout_width="wrap_content"
    	    android:layout_height="wrap_content"
    	    android:text="No! Me!"
    	    android:textSize="20dp"
    	    android:layout_gravity="center"/>
    </TableRow>
</TableLayout>
</LinearLayout>

The ImageButtons background attribute has been set to transparent, i.e. android:background="@android:color/transparent". This is to remove the ImageButton's default state rectangles. No code is required to see the ImageButtons in action, however the following code shows the buttons in use (here simply counting the button presses).

public class ButtonPressActivity extends Activity {
    TextView tv1;	//for storing TextView references
    TextView tv2;
    long howManyClicks1=0L;	//count button clicks
    long howManyClicks2=0L;	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        //get reference to the TextViews for later use
        tv1 = (TextView) findViewById(R.id.textview1);
        tv2 = (TextView) findViewById(R.id.textview2);
        //attach an instance of HandleClick to the ImageButtons
        HandleClick hc=new HandleClick();
        findViewById(R.id.button1).setOnClickListener(hc);
        findViewById(R.id.button2).setOnClickListener(hc);
    }    
    private class HandleClick implements OnClickListener{
        public void onClick(View arg0) {
            if(arg0.getId()==R.id.button1) 
	       	tv1.setText("Pressed: " + ++howManyClicks1);
	    else
	       	tv2.setText("Pressed: " + ++howManyClicks2);
        }
    }
}

This example used circular buttons, many other shapes and styles can be achieved with Inkscape.

See Also:

[1]

[2]

[3]

[4]

[5]

[6]

Download:

The source code for this project can be downloaded from http://tekeye.biz/download/buttonpress.zip.
No records found.