Skip to content

Posts tagged ‘tutorial’

Android: Creating a custom Adapter for GridView (ButtonAdapter)

Sep 8 10
by mat

Background
Adapters are great, it’s a fact. After you get over the initial learning curve you will realise you love them (almost as much as a six sided companion). This is my attempt at a casual explanation of how to create your own custom adapter, in this example we will create a ButtonAdapter similar to something you might see in a soundboard (yawn).

Example of a grid adapter in use

Example of a grid adapter in use

Advantages of an adapter

  • Dynamic – Can expand to any number of elements rather than statically coding each individual view.
  • Elegant – Makes your code petite and quite clear to understand once you get over the initial difficulty
  • Beautiful – Now you don’t have to control how many items there are in rows or columns, android will automatically fill up the screen in the best way possible. This also means you don’t need to redesign your application for horizontal and vertical orientations.

Creating a ButtonAdapter

So we’re going to dive straight into the deep end and create our own ButtonAdapter class that extends the BaseAdapter class. If you are doing this in eclipse you can write the first line and then it will offer to autocreate (implement) the missing methods for you (if you highlight the error). This code goes inside your Activity in your java file but not inside your oncreate method.

public class ButtonAdapter extends BaseAdapter {
 private Context mContext;

 // Gets the context so it can be used later
 public ButtonAdapter(Context c) {
  mContext = c;
 }

 // Total number of things contained within the adapter
 public int getCount() {
  return filenames.length;
 }

  // Require for structure, not really used in my code.
 public Object getItem(int position) {
  return null;
 }

 // Require for structure, not really used in my code. Can
 // be used to get the id of an item in the adapter for 
 // manual control. 
 public long getItemId(int position) {
  return position;
 }

 public View getView(int position, 
                           View convertView, ViewGroup parent) {
  Button btn;
  if (convertView == null) {  
   // if it's not recycled, initialize some attributes
   btn = new Button(mContext);
   btn.setLayoutParams(new GridView.LayoutParams(100, 55));
   btn.setPadding(8, 8, 8, 8);
   } 
  else {
   btn = (Button) convertView;
  }
  exus
  btn.setText(filesnames[position]); 
  // filenames is an array of strings
  btn.setTextColor(Color.WHITE);
  btn.setBackgroundResource(R.drawable.button);
  btn.setId(position);

  return btn;
 }
}

So the important methods are getCount and getView. getCount returns the number of objects (in our case buttons) that will be needed in this adapter. getView returns an object (again a button in our case) so that it can be used.

Both these functions reference an array that I have referered to as filenames this is a string array (String[]) which looks something like the following:

public String[] filesnames = { 
			"File 1", 
			"File 2",
			"Roflcopters"
			};

Creating an OnClickListener

You can add the following to your getView method to setup a new onclick listener for your buttons so that they can react to button presses.

  // Set the onclicklistener so that pressing the button fires an event
  // We will need to implement this onclicklistner.
  btn.setOnClickListener(new MyOnClickListener(position));

For this to work we need to implement our own OnClickListner which I have named MyOnClickListener (for lack of a better name) this is the same as a normal onclick listner except we pass an integer so that we can tell which button called our onClick method (you could get the id from the view passed, but this method is useful when expanding your program later on).


class MyOnClickListener implements OnClickListener
{
 private final int position;

 public MyOnClickListener(int position)
 {
  this.position = position;
 }

 public void onClick(View v)
 {
  // Preform a function based on the position
  someFunction(this.position)
 }
}

Implementing this adapter

Now implementing the adapater is very simple, add a few imports and load a grid view from an xml file. Then we simply set the gridview’s adapter to be a new ButtonAdapter and it will automatically do the rest for us.

// You will need the following imports

import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.GridView;

// In your oncreate (or where ever you want to create your gridview)
GridView gridview = (GridView) findViewById(R.id.gridview);
gridview.setAdapter(new ButtonAdapter(this));

And hopefully your all done, you could then go on to add a context menu(menu on long press) to your buttons. If you have any questions or want something explaining a bit better, just ask!

Making Prettier Buttons in android; XML (rollover,selection & focus effects), 9patch images and transparency

Aug 23 10
by mat

Alot of the soundboards out there on the market look a little bit ugly by using the default android buttons in conjunction with a background (no offense to developers of these, perhaps they can learn from this); this mini-tutorial explains how to use xml to create a customised nice looking button thing.

Ugly Buttons:
Below is show the example I will use to demonstrate the default buttons in use with a background image (It’s a picture of me hugging the android statue!)

"Ugly" default buttons in android

Button States

There are four images you will need to create (you can use less if you want); one for each of the following states:

state_focused state_pressed What this means
true false Button highlighted (selected with trackpad)
true true Button foussed and pressed
false true Button pressed
false false Normal state of button

I recommend creating a nine-patch png for the button image, this way your image can be stretched to fit the button size as needed. Also soundboards look rather snazzy if you include a background image, and then you can use transparency in your png so that your buttons don’t obscure it.

draw9patch tool button android

Using draw9patch tool to make a 9patch png for use as a strechable button

XML Code

button.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_focused="true"
	android:state_pressed="false" 
	android:drawable="@drawable/button_selected" />
    <item android:state_focused="true" 
    	  android:state_pressed="true"
    	  android:drawable="@drawable/button_focus" />
    <item android:state_focused="false" 
    	  android:state_pressed="true"
	  android:drawable="@drawable/button_pressed" />  
    <item android:drawable="@drawable/button_normal" />
</selector>

main.xml
An example usage of how to use this newly created xml button in your layout file.

<Button
android:id="@+id/mysexynewbutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30sp"
android:textStyle="bold"
android:text="Stealthcopter FTW"
android:background="@drawable/button" />

Results
Now you should have some nice sexy customised buttons that change depending on thier state. Which makes our example now look like this (I increased the padding and margins of the buttons slightly):

Pretty Buttons with transparency using 9patch png and xml

Pretty Buttons with transparency using 9patch png and xml

Below are a few examples of my work with some nice transparent buttons:

Example 9 patch image

button.9.png

button.9.png

Android: Soundpool vs MediaPlayer (focus on soundboards and memory problems)

Aug 18 10
by mat

I get a fair few emails asking for help on making soundboards because I have a few out on the market currently, so this is one of a few mini-tutorials I am creating to explain some of the difficulties to overcome.

So there are two methods for playing sounds in android SoundPool and MediaPlayer.

SoundPool

SoundPool is designed for short clips which can be kept in memory decompressed for quick access, this is best suited for sound effects in apps or games. Using this method with soundboards is a bad idea as you will be loading lots of “medium” sized sounds into the memory and you may exceed your limit (16Mb) and get an OutOfMemoryException.

MediaPlayer

MediaPlayer is designed for longer sound files or streams, this is best suited for music files or larger files. The files will be loaded from disk each time create is called, this will save on memory space but introduce a small delay (not really noticeable).

So lets have a look how to use Media Player instead of SoundPool

MediaPlayer Usage

MediaPlayer mp = MediaPlayer.create(ClassName.this, R.raw.sound);
mp.start();

Where ClassName.this should be the name of your class (Hint: this should be the name of the java file you are editing)

You can pause the sound playing and then use start to start the sound playing again.

mp.pause(); // Stop
mp.start();   // Start from place paused

To stop the sound playing use stop, using start now will start playing the sound again from the beginning

mp.stop();    // Stop sound
mp.start();   // Start from beginning

To reset the media player so it can be reinitialised with a another sound

mp.reset();
mp = MediaPlayer.create(ClassName.this, R.raw.sound2);

To release the resources once you are finished media player (free memory)

mp.release();

My Soundboards

Below are a few screenshots of my current soundboards on the market