Sunday 1 June 2014

Making three state custom button in android


Today I'll discuss how can we make three state button like repeat song button in android music app.
First of all we need to define xml custom attributes for our custom button. Our repeat button has three states:
  1. Repeat One.
  2. Repeat All.
  3. Repeat Off.
So we need to define xml attributes for:
  1. src_repeat_one => Source drawable to be shown for Repeat One.
  2. src_repeat_all   => Source drawable to be shown for Repeat All.
  3. src_repeat_off  => Source drawable to be shown for Repeat Off.
plus, we also need another xml attribute to set the current state:
     repeat_state => which can be 0, 1 or 2 (off, on , all).

So lets create attr.xml in values folder of our android project.

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

    <!-- repeat state -->
    <attr name="repeat_state">
        <enum name="off" value="0" />
        <enum name="one" value="1" />
        <enum name="all" value="2" />
    </attr>

    <!-- custom repeat button -->
    <declare-styleable name="RepeatButton">
        <attr name="repeat_state" />
        <attr name="src_repeat_off" format="integer" />
        <attr name="src_repeat_one" format="integer" />
        <attr name="src_repeat_all" format="integer" />
    </declare-styleable>

</resources> 


Now, we will make Repeat button by extending the imageButton:

RepeatButton.xml:

public class RepeatButton extends ImageButton {

    private final int MAX_STATES=3;
    int state;
    Drawable srcRepeatOff;
    Drawable srcRepeatOne;
    Drawable srcRepeatAll;
    int repeatState;
    Context context;
    

    public RepeatButton(Context context) {
        super(context);
        this.context=context;

    }

    public RepeatButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context=context;

        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.RepeatButton);

        try {

            repeatState = a
                    .getInteger(R.styleable.RepeatButton_repeat_state, 0);
            srcRepeatOff = a
                    .getDrawable(R.styleable.RepeatButton_src_repeat_off);
            srcRepeatOne = a
                    .getDrawable(R.styleable.RepeatButton_src_repeat_one);
            srcRepeatAll = a
                    .getDrawable(R.styleable.RepeatButton_src_repeat_all);

        } catch (Exception e) {

        } finally {
            a.recycle();
        }

        switch (repeatState) {
        case 0:
            this.setBackground(srcRepeatOff);
            break;
        case 1:
            this.setBackground(srcRepeatOne);
            break;
        case 2:
            this.setBackground(srcRepeatAll);
            break;
        default:
            break;

        }
    }

    @Override
    public boolean performClick() {
        super.performClick();
        nextState();
        setStateBackground();
        return true;

    }
    
    private void nextState() {
        state++;

        if (state == MAX_STATES) {
            state = 0;
        }
    }

    private void setStateBackground() {

        switch (state) {
        case 0:
            this.setBackground(srcRepeatOff);
            showButtonText("Repeat Off");
            break;
        case 1:
            this.setBackground(srcRepeatOne);
            showButtonText("Repeat One");
            break;
        case 2:
            this.setBackground(srcRepeatAll);
            showButtonText("Repeat All");
            
            break;
        default:
            break;

        }
    }
    public void showButtonText(String text) {

        Toast.makeText(context, text, Toast.LENGTH_SHORT).show();

    }
    public REPEAT getRepeatState() {

        switch (state) {
        case 0:
            return REPEAT.OFF;
        case 1:
            return REPEAT.ONE;
        case 2:
            return REPEAT.ALL;
        default:
            return REPEAT.OFF;

        }
    }

    public void setRepeatState(REPEAT repeatState) {

        switch (repeatState) {
        case OFF:
            state=0;

            break;
        case ONE:
            state=1;
            break;
        case ALL:
            state=2;
            break;
        default:
            break;
        }

        setStateBackground();
    }
}


We retrieve xml attributes and set the imageButton values accordingly. PerformClick is called whenever user press the button, so we change the button state here. REPEAT is an enum define like this:

public enum REPEAT {
     OFF,ONE,ALL;
}

getRepeatState and setRepeatState methods are not necessary and  provided only to change button state programatically.

We have created all the necessary components of our custom button. Now lets use it in our layout, activity_main.xml


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <sohail.aziz.samplebutton.RepeatButton
        android:id="@+id/btRepeat"
        android:layout_width="60dp"
        android:layout_height="40dp"
        android:layout_marginRight="100dp"
        android:padding="5dp"
        app:repeat_state="off"
        app:src_repeat_all="@drawable/repeat_enable"
        app:src_repeat_off="@drawable/repeat_disable"
        app:src_repeat_one="@drawable/repeat_enable_1" />

 . . . . . 

</LinearLayout>


Pay attention to xmlns:app="http://schemas.android.com/apk/res-auto" this is necessary for using custom attributes in your layouts. The layout (with three buttons, different states) will look like this:




Complete source code can be found here three-state-button .
    
     

No comments:

Post a Comment