自定義View的步驟
通過繼承view類自定義view步驟如下
- 實現view構造方法
- 測量view的大小,即重寫onMeasure方法
- 繪製view,即重寫onDraw方法
繼承自view一般不需要重寫onLayout方法
這次我們實現一個滑動的開關,效果見圖:
代碼中有詳細的註釋如下:
package com.car.customview.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import com.car.customview.R;
public class MyToggleButton extends View implements View.OnClickListener {
/*
繼承View自定義View步驟:
1.構造方法
2.測量view大小
3.確定view的位置,view有建議權,決定權在父view手中
4.繪製view
*/
//背景圖片
private Bitmap backgroundBitmap;
//可以滑動的圖片
private Bitmap slideBtn;
private Paint paint;
private float slideBtn_left = 0;
private boolean currState = false;//當前狀態
private boolean isDrag = false;//是否拖動了
public MyToggleButton(Context context) {
super(context);
initView();
}
public MyToggleButton(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
//獲得自定義屬性
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyToggleButton);
currState = typedArray.getBoolean(R.styleable.MyToggleButton_curr_state,false);
int backgroundId = typedArray.getResourceId(R.styleable.MyToggleButton_background, 0);
backgroundBitmap = BitmapFactory.decodeResource(getResources(), backgroundId);
int slideBtnId = typedArray.getResourceId(R.styleable.MyToggleButton_toggle_btn, 0);
slideBtn = BitmapFactory.decodeResource(getResources(), slideBtnId);
initView();
}
public MyToggleButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
//view的大小設置爲背景圖片的寬高
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(backgroundBitmap.getWidth(), backgroundBitmap.getHeight());
}
//onDraw方法中要注意drawBitmap調用的順序,後調用的會覆蓋在前面調用的上面
@Override
protected void onDraw(Canvas canvas) {
/*
這兩句代碼順序如果顛倒,則會導致背景圖片覆蓋在滑動按鈕上層
*/
//繪製背景
canvas.drawBitmap(backgroundBitmap,0,0,paint);
//繪製滑動的按鈕
canvas.drawBitmap(slideBtn, slideBtn_left, 0, paint);
}
private void initView() {
paint = new Paint();
paint.setAntiAlias(true);//抗鋸齒
setOnClickListener(this);
flushState();
}
@Override
public void onClick(View v) {
//如果沒有拖動才執行click事件
if (!isDrag){
currState = !currState;
flushState();
}
}
private void flushState() {
if (currState){
slideBtn_left = backgroundBitmap.getWidth() - slideBtn.getWidth();
}else {
slideBtn_left = 0;
}
flushView();//刷新View,會調用onDraw方法
}
private int firstX;
private int lastX;
//該方法中處理view滑動
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
firstX = lastX = (int) event.getX();
isDrag = false;
break;
case MotionEvent.ACTION_MOVE:
if (Math.abs(event.getX() - firstX) > 5){
isDrag = true;
}
int distance = (int) (event.getX() - lastX);
lastX = (int) event.getX();
slideBtn_left += distance;
break;
case MotionEvent.ACTION_UP:
//擡起時根據button位置確定當前狀態
if (isDrag){
int maxLeft = backgroundBitmap.getWidth() - slideBtn.getWidth();
if (slideBtn_left > maxLeft / 2){
currState = true;
}else {
currState = false;
}
flushState();
}
break;
default:
}
//刷新視圖,button就會滑動
flushView();
return true;
}
private void flushView() {
//直接刷新,滑動的button會滑到view外部,所以要進行判斷
int maxLeft = backgroundBitmap.getWidth() - slideBtn.getWidth();//最大的左邊界
slideBtn_left = slideBtn_left > 0 ? slideBtn_left : 0;
slideBtn_left = slideBtn_left < maxLeft ? slideBtn_left : maxLeft;
invalidate();
}
}
自定義屬性步驟:
- 在vlaues文件夾下新建attrs.xml,定義自己的屬性集
- 在佈局文件中使用自定義屬性時需要聲明命名空間xmlns:app=“http://schemas.android.com/apk/res-auto”
- 在view第二個構造方法中解析自定義屬性
滑動開關的自定義屬性如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyToggleButton">
<!--背景圖-->
<attr name="background" format="reference" />
<!--滑動的按鈕圖-->
<attr name="toggle_btn" format="reference" />
<!--默認狀態-->
<attr name="curr_state" format="boolean" />
</declare-styleable>
</resources>
在佈局文件中直接使用滑動開關:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.car.customview.view.MyToggleButton
android:id="@+id/toggle_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:background="@drawable/switch_background"
app:toggle_btn="@drawable/slide_button"
app:curr_state="true"/>
</LinearLayout>