Easy Tutorial
❮ Css Position Static Relative Absolute Fixed Javascript Console Object ❯

2.3.3 Button and ImageButton

Category Android Basic Tutorial

Introduction:

>

Today, we will introduce two basic Android control widgets: the Button and the ImageButton. The usage of ImageButton is quite similar to Button, and its image-related features are the same as those of the ImageView, which we will cover later. Therefore, this section will focus on the Button. Note that Button is a subclass of TextView, so many properties of TextView can also be applied to Button. In practical development, we often need to handle different states of a button, such as changing its color when pressed, released, or disabled. This can be achieved using the StateListDrawable resource, which involves creating a drawable resource file. Let's dive into the details.


1. Introduction to StateListDrawable:

>

StateListDrawable is a type of Drawable resource that allows you to set different images for different states, using the key node <selector>. By setting the background property of a Button to this drawable resource, you can easily achieve different colors or backgrounds when the button is pressed.

Attributes we can set:

>


2. Implementing Button Press Effects:

First, prepare three background images. To prevent button distortion, it's common to use .9.png images for button drawables. Here's a look at the running effect:

Code Implementation:

<?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/ic_course_bg_fen"/>
    <item android:state_enabled="false" android:drawable="@drawable/ic_course_bg_pressed"/>
    <item android:drawable="@drawable/ic_course_bg_cheng"/>
</selector>

Layout File: activity_main.xml

<Button
        android:id="@+id/btnOne"
        android:layout_width="match_parent"
        android:layout_height="64dp"
        android:background="@drawable/btn_bg1"
        android:text="Button"/>

    <Button
        android:id="@+id/btnTwo"
        android:layout_width="match_parent"
        android:layout_height="64dp"
        android:text="Button Disabled"/>

MainActivity.java:

public class MainActivity extends Activity {

    private Button btnOne, btnTwo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnOne = (Button) findViewById(R.id.btnOne);
        btnTwo = (Button) findViewById(R.id.btnTwo);
        btnTwo.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if(btnTwo.getText().toString().equals("Button Disabled")){
                    btnOne.setEnabled(false);
                    btnTwo.setText("Button Enabled");
                }else{
                    btnOne.setEnabled(true);
                    btnTwo.setText("Button Disabled");
                }
            }
        });
    }
}

3. Drawing Round Buttons with Color Values

>

Sometimes, we may not have a designer, or we may not want to create images ourselves. In such cases, we can programmatically set the button background to any color we want. Below, we will create a round button background using color values. This involves using another drawable resource: ShapeDrawable. We won't go into detail here, but you can use it as shown.

Effect Image:

bbutondangerrounded.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_pressed="true"><shape>
            <solid android:color="@color/bbutton_danger_pressed" />
            <stroke android:width="1dp" android:color="@color/bbutton_danger_edge" />
            <corners android:radius="@dimen/bbuton_rounded_corner_radius"/>
        </shape></item>

    <item android:state_enabled="false"><shape>
        <solid android:color="@color/bbutton_danger_disabled" />
            <stroke android:width="1dp" android:color="@color/bbutton_danger_disabled_edge" />
            <corners android:radius="@dimen/bbuton_rounded_corner_radius"/>
        </shape></item>

    <item><shape>
            <solid android:color="@color/bbutton_danger" />
            <stroke android:width="1dp" android:color="@color/bbutton_danger_edge" />
            <corners android:radius="@dimen/bbuton_rounded_corner_radius"/>
        </shape></item>

</selector>

color.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="bbutton_danger_pressed">#ffd2322d</color>
    <color name="bbutton_danger_edge">#ffd43f3a</color>
    <color name="bbutton_danger_disabled">#a5d9534f</color>
    <color name="bbutton_danger_disabled_edge">#a5d43f3a</color>
    <color name="bbutton_danger">#ffd9534f</color>
    <color name="text_font_white">#FFFFFF</color>
</resources>

dimens.xml:

<dimen name="bbuton_rounded_corner_radius">5dp</dimen>

4. Implementing Material Design Ripple Effect Button

If you have an Android device running Lollipop (5.0) or above, you might be familiar with the ripple effect when clicking buttons:

Effect Image:

The fast ripple is the effect when the button is pressed, and the slow ripple is the effect when the button is long-pressed.

Implementation Logic:

  1. We inherit from ImageButton, though you can use Button or View. Here, we chose ImageButton to center the image.
  2. We create two Paint objects: one for drawing the background color and one for drawing the ripple effect.
  3. We calculate the maximum radius and increment the starting radius periodically until it reaches the maximum radius, then reset the state.

Implementation Code:

Custom ImageButton: MyButton.java

package demo.com.jay.buttondemo;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.widget.ImageButton;

/**
 * Created by coder-pig on 2015/7/16 0016.
 */
public class MyButton extends ImageButton {

    private static final int INVALIDATE_DURATION = 15;     // Time interval for each refresh
    private static int DIFFUSE_GAP = 10;                  // Increment for diffusion radius
    private static int TAP_TIMEOUT;                         // Time to determine click and long press

    private int viewWidth, viewHeight;                   // Width and height of the control
    private int pointX, pointY;                          // Coordinates of the control origin (top-left)
    private int maxRadio;                             // Maximum radius of diffusion
    private int shaderRadio;                        // Radius of diffusion

    private Paint bottomPaint, colorPaint;          // Paints: background and ripple
    private boolean isPushButton;                 // Records if the button is pressed

    private int eventX, eventY;                  // X, Y coordinates of the touch position
    private long downTime = 0;                 // Time of press

    public MyButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        initPaint();
        TAP_TIMEOUT = ViewConfiguration.getLongPressTimeout();
    }

    /*
    * Initialize the paint
    * */
    private void initPaint() {
        colorPaint = new Paint();
        bottomPaint = new Paint();
        colorPaint.setColor(getResources().getColor(R.color.reveal_color));
        bottomPaint.setColor(getResources().getColor(R.color.bottom_color));
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (downTime == 0) downTime = SystemClock.elapsedRealtime();
                eventX = (int) event.getX();
                eventY = (int) event.getY();
                // Calculate the maximum radius:
                countMaxRadio();
                isPushButton = true;
                postInvalidateDelayed(INVALIDATE_DURATION);
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                if(SystemClock.elapsedRealtime() - downTime < TAP_TIMEOUT){
                    DIFFUSE_GAP = 30;
                    postInvalidate();
                }else{
                    clearData();
                }
                break;
        }
        return super.onTouchEvent(event);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        if(!isPushButton) return; // Return if the button is not pressed
        // Draw the background after pressing
        canvas.drawRect(pointX, pointY, pointX + viewWidth, pointY + viewHeight, bottomPaint);
        canvas.save();
        // Draw the diffused circular background
        canvas.clipRect(pointX, pointY, pointX + viewWidth, pointY + viewHeight);
        canvas.drawCircle(eventX, eventY, shaderRadio, colorPaint);
        canvas.restore();
        // Until the radius equals the maximum radius
        if(shaderRadio < maxRadio){
            postInvalidateDelayed(INVALIDATE_DURATION,
                    pointX, pointY, pointX + viewWidth, pointY + viewHeight);
            shaderRadio += DIFFUSE_GAP;
        }else{
            clearData();
        }
    }

    /*
        * Method to calculate the maximum radius
        * */
    private void countMaxRadio() {
        if (viewWidth > viewHeight) {
            if (eventX < viewWidth / 2) {
                maxRadio = viewWidth - eventX;
            } else {
                maxRadio = viewWidth / 2 + eventX;
            }
        } else {
            if (eventY < viewHeight / 2) {
                maxRadio = viewHeight - eventY;
            } else {
                maxRadio = viewHeight / 2 + eventY;
            }
        }
    }

    /*
    * Method to reset data
    * */
    private void clearData(){
        downTime = 0;
        DIFFUSE_GAP = 10;
        isPushButton = false;
        shaderRadio = 0;
        postInvalidate();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        this.viewWidth = w;
        this.viewHeight = h;
    }
}
<code>
<p><b>color.xml:</b></p>
<pre>
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="reveal_color">#FFFFFF</color>
    <color name="bottom_color">#3086E4</color>
    <color name="bottom_bg">#40BAF8</color>
</resources>

activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    &lt;demo.com.jay.buttondemo.MyButton
        android:id="@+id/myBtn"
        android:layout_width="match_parent"
        android:layout_height="64dp"
        android:src="@mipmap/ic_tur_icon"
        android:background="@color/bottom_bg"
        android:scaleType="center"/>

</RelativeLayout>

Source code download (AS project): ButtonDemo.zip


Summary:

This section introduces some practical uses of Button in development. Some concepts might be unfamiliar, but they will be explained in detail later. Thank you!

-1.0 Android Basic Introduction Tutorial

-1.0.1 2015 Latest Android Basic Introduction Tutorial Table of Contents

Follow on WeChat

❮ Css Position Static Relative Absolute Fixed Javascript Console Object ❯