自定义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>