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:
>
- drawable: Reference to a Drawable bitmap, typically representing the normal state of the component.
- state_focused: Whether the component is focused.
- statewindowfocused: Whether the window containing the component is focused.
- state_enabled: Whether the component is enabled.
- state_checkable: Whether the component can be checked, e.g., a checkbox.
- state_checked: Whether the component is checked.
- state_selected: Whether the component is selected, useful for scrollable components.
- state_pressed: Whether the component is pressed.
- state_active: Whether the component is active, e.g., a sliding tab.
- state_single: For components with multiple child components, whether only one is displayed.
- state_first: For components with multiple child components, whether the first one is displayed.
- state_middle: For components with multiple child components, whether the middle one is displayed.
- state_last: For components with multiple child components, whether the last one is displayed.
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:
- We inherit from ImageButton, though you can use Button or View. Here, we chose ImageButton to center the image.
- We create two Paint objects: one for drawing the background color and one for drawing the ripple effect.
- 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">
<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
- 1.1 Background and System Architecture Analysis
- 1.2 Development Environment Setup
- 1.2.1 Developing Android Apps with Eclipse + ADT + SDK
- 1.2.2 Developing Android Apps with Android Studio
- 1.3 Solving SDK Update Issues
- 1.4 Genymotion Emulator Installation
- 1.5.1 Git Tutorial: Basic Operations on Local Repositories
- 1.5.2 Using GitHub to Set Up a Remote Repository with Git
- 1.6 How to Use 9-Patch Images
- 1.7 Interface Prototype Design
- 1.8 Project-Related Analysis (Various Files, Resource Access)
- 1.9 Android Application Signing and Packaging
- 1.11 Decompiling APK to Retrieve Code & Resources
- 2.1 Concepts of View and ViewGroup
- 2.2.1 LinearLayout (Linear Layout)
- 2.2.2 RelativeLayout (Relative Layout)
- 2.2.3 TableLayout (Table Layout)
- 2.2.4 FrameLayout (Frame Layout)
- 2.2.5 GridLayout (Grid Layout)
- 2.2.6 AbsoluteLayout (Absolute Layout)
- 2.3.1 Detailed Explanation of TextView (Text Field)
- 2.3.2 Detailed Explanation of EditText (Input Field)
- 2.3.3 Button (Button) and ImageButton (Image Button)
- 2.3.4 ImageView (Image View)
- 2.3.5 RadioButton (Radio Button) & Checkbox (Checkbox)
- 2.3.6 ToggleButton and Switch
- 2.3.7 ProgressBar (Progress Bar)
- 2.3.8 SeekBar (Drag Bar)
- 2.3.9 RatingBar (Star Rating Bar)
- 2.4.1 ScrollView (Scroll Bar)
- 2.4.2 Date & Time Components (Part 1)
- 2.4.3 Date & Time Components (Part 2)
- 2.4.4 Basic Adapter Explanation
- 2.4.5 Simple Usage of ListView
- 2.4.6 Optimization of BaseAdapter
- 2.4.7 Focus Issues with ListView
- 2.4.8 Solving Checkbox Misalignment in ListView
- 2.4.9 Data Update Issues in ListView
- 2.5.0 Building a Reusable Custom BaseAdapter
- 2.5.1 Implementing Multiple Item Layouts in ListView
- 2.5.2 Basic Usage of GridView (Grid View)
- 2.5.3 Basic Usage of Spinner (List Option Box)
- 2.5.4 Basic Usage of AutoCompleteTextView (Auto-Complete Text Field)
- 2.5.5 Basic Usage of ExpandableListView (Collapsible List)
- 2.5.6 Basic Usage of ViewFlipper (Flip View)
- 2.5.7 Basic Usage of Toast
- 2.5.8 Detailed Explanation of Notification (Status Bar Notification)
- 2.5.9 Detailed Explanation of AlertDialog (Dialog Box)
- 2.6.0 Basic Usage of Other Common Dialogs
- 2.6.1 Basic Usage of PopupWindow (Floating Box)
- 2.6.2 Menu (Menu)
- 2.6.3 Simple Usage of ViewPager
- 2.6.4 Simple Usage of DrawerLayout (Official Side Sliding Menu)
- 3.1.1 Event Handling Mechanism Based on Listeners
- 3.2 Event Handling Mechanism Based on Callbacks
- 3.3 Analysis of Handler Message Passing Mechanism
- 3.4 TouchListener vs OnTouchEvent + Multi-Touch
- 3.5 Listening for Content Changes in EditText
- 3.6 Responding to System Setting Changes (Configuration Class)
- 3.7 AsyncTask Asynchronous Tasks
- 3.8 Gestures (Gestures)
- 4.1.1 Activity: Beginner's Guide
- 4.1.2 Activity: Intermediate Guide
- 4.1.3 Activity: Advanced Guide
- 4.2.1 Service: Introduction
- 4.2.2 Service: Intermediate
- 4.2.3 Service: Advanced
- 4.3.1 BroadcastReceiver: Basic
- 4.3.2 BroadcastReceiver: Advanced
- 4.4.1 ContentProvider: Introduction
- 4.4.2 ContentProvider: Further Exploration - Document Provider
- 4.5.1 Basic Usage of Intent
- 4.5.2 Passing Complex Data with Intent
- 5.1 Basic Overview of Fragment
- 5.2.1 Fragment Example: Bottom Navigation Bar Implementation (Method 1)
- 5.2.2 Fragment Example: Bottom Navigation Bar Implementation (Method 2)
- 5.2.3 Fragment Example: Bottom Navigation Bar Implementation (Method 3)
- 5.2.4 Fragment Example: Bottom Navigation Bar + ViewPager for Swiping Between Pages
- 5.2.5 Fragment Example - Simple Implementation of News (Shopping) App List Fragment
6.2 Data Storage and Access - SharedPreferences for Saving User Preferences
6.3.1 Data Storage and Access - Introduction to SQLite Database
6.3.2 Data Storage and Access - Further Exploration of SQLite Database
7.1.1 Android Network Programming Essentials and HTTP Protocol Study
7.5.3 Important Considerations for WebView in Android 4.4 and Later
8.3.4 Paint API - Xfermode and PorterDuff Detailed Explanation (Part 1)
8.3.5 Paint API - Xfermode and PorterDuff Detailed Explanation (Part 2)
8.3.6 Paint API - Xfermode and PorterDuff Detailed Explanation (Part 3)
8.3.7 Paint API - Xfermode and PorterDuff Detailed Explanation (Part 4)
8.3.8 Paint API - Xfermode and PorterDuff Detailed Explanation (Part 5)
8.3.14 Paint Enum/Constant Values and ShadowLayer Shadow Effect
8.3.17 Canvas API Detailed Explanation (Part 2) Clipping Methods Collection
8.3.18 Canvas API Detailed Explanation (Part 3) Matrix and drawBitmapMesh
8.4.3 Android Animation Collection - Property Animation - Introduction
8.4.4 Android Animation Collection - Property Animation - Further Exploration
11.0 "2015 Latest Android Basic Beginner's Guide" Completion Celebration
12.2 DrySister Meets Girls App (Version 1) - 2. Parsing Backend Data
12.4 DrySister View Girls App (Version 1) – 4. Adding Data Caching (Integrating SQLite)
12.5 DrySister View Girls App (Version 1) – 5. Code Review, Adjustments, and Logging Class Writing