一、效果图

二、主要技术点
1.自定义View
2.自定义属性
三、自定义控件的步骤
1.自定义类继承自View或View的子类;
2.重写构造方法
(1)MyView(Context); // 在代码中new 对象时调用此方法
(2)MyView(Context,AttributeSet); // 在XML布局文件中声明此View,创建对象时,由系统自动调用
(3)MyView(Context,AttributeSet,int); // 与方法2用法一样,只是多了一个参数:默认样式
3.重写相关方法,实现我们的需求,一般要重写的方法:
(1)onMeasure(int,int); // 系统测量控件大小时调用该方法
(2)onLayout(boolean,int,int,int,int); // 系统为该view 指定位置时调用此方法,子view的位置,自身只有建议权,决定权在父view的手中。一般不需要重写。
(3)onDraw(Canvas); // 为本view绘制内容时,调用该方法。
四、为新控件添加自定义属性的步骤:
1.在attrs.xml文件中声明属性,有属性名(name)和格式(format)。如
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 声明属性集的名称 -->
<declare-styleable name="MyToggleBtn">
<!-- 声名一个属性 name是my_background 类型为 引用类型 引用资源ID -->
<attr name="my_background" format="reference" />
<!-- 声名一个属性 name是my_slide_btn 类型为 引用类型 引用资源ID -->
<attr name="my_slide_btn" format="reference" />
<!-- 声名一个属性 name是curr_state 类型为 boolean 类型 -->
<attr name="curr_state" format="boolean" />
</declare-styleable>
</resources>
2.在布局文件中使用新属性,使用之前必须先声明命名空间,如xmlns:gnnuit="http://schemas.android.com/apk/res/com.gnnuit.togglebutton",其中“http://schemas.android.com/apk/res/”为Android固定的格式,“com.gnnuit.togglebutton”为应用程序的包名,与AndroidManifest.xml声明的包名一样。
<com.gnnuit.togglebutton.MyToggleButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
gnnuit:curr_state="true"
gnnuit:my_background="@drawable/switch_background"
gnnuit:my_slide_btn="@drawable/slide_button" />
3.在自定义View的构造方法中,通过解析AttributeSet对象,获得所需要的属性值。
四。核心代码
package com.gnnuit.togglebutton;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class MyToggleButton extends View implements android.view.View.OnClickListener {
private Bitmap backgroundBitmap;// 背景图片
private Bitmap slideButtonBitmap;// 滑动按钮图片
private Paint paint;
private boolean currentState = false;// 当前状态
private float left_slide;// 滑动按钮的左边界位置
private float startX, lastX;// 记录滑动按钮滑动时的开始和结束位置
private boolean isSlide = false;// 记录是否移动滑动按钮
private float dist;
/**
* 在布局文件中声明此View,创建时由系统自动调用该构造方法
*
* @param context
* @param attrs
*/
public MyToggleButton(Context context, AttributeSet attrs) {
super(context, attrs);
// 获取自定义属性
currentState = attrs.getAttributeBooleanValue("http://schemas.android.com/apk/res/com.gnnuit.togglebutton", "curr_state", false);
int backgroundResourceId = attrs.getAttributeResourceValue("http://schemas.android.com/apk/res/com.gnnuit.togglebutton", "my_background", -1);
if (backgroundResourceId == -1) {
throw new RuntimeException("请设置背景图片");
}
backgroundBitmap = BitmapFactory.decodeResource(getResources(), backgroundResourceId);
int slideBtnResourceId = attrs.getAttributeResourceValue("http://schemas.android.com/apk/res/com.gnnuit.togglebutton", "my_slide_btn", -1);
if (slideBtnResourceId == -1) {
throw new RuntimeException("请设置背景图片");
}
slideButtonBitmap = BitmapFactory.decodeResource(getResources(), slideBtnResourceId);
if (currentState) {
left_slide = backgroundBitmap.getWidth() - slideButtonBitmap.getWidth();
}
initView();// 初始化
}
/**
* 初始化
*/
private void initView() {
// 初始化图片
// backgroundBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.switch_background);
// slideButtonBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.slide_button);
// 初始化画笔
paint = new Paint();
paint.setAntiAlias(true);// 设置抗锯齿
// 设置点击事件
setOnClickListener(this);
}
@Override
/**
* 测量尺寸的回调方法
*/
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(backgroundBitmap.getWidth(), backgroundBitmap.getHeight());// 设置控件的宽和高,单位是像素
}
@Override
/**
* 绘制当前View的内容
*/
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(backgroundBitmap, 0, 0, paint);
canvas.drawBitmap(slideButtonBitmap, left_slide, 0, paint);
}
@Override
public void onClick(View v) {
if (!isSlide) {
currentState = !currentState;
flushState();// 刷新界面
}
}
/**
* 刷新当前状态
*/
private void flushState() {
if (currentState) {
left_slide = backgroundBitmap.getWidth() - slideButtonBitmap.getWidth();
} else {
left_slide = 0;
}
invalidate();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isSlide = false;
startX = lastX = event.getX();
break;
case MotionEvent.ACTION_MOVE:
lastX = event.getX();
dist = lastX - startX;
if (Math.abs(dist) > 5) {
isSlide = true;
left_slide += dist;
flushShow();
startX = event.getX();
}
break;
case MotionEvent.ACTION_UP:
if (isSlide) {
if (left_slide > (backgroundBitmap.getWidth() - slideButtonBitmap.getWidth()) / 2) {
left_slide = backgroundBitmap.getWidth() - slideButtonBitmap.getWidth();
currentState = true;
} else {
left_slide = 0;
currentState = false;
}
flushShow();
}
break;
}
return true;
}
/**
* 刷新当前View
*/
private void flushShow() {
int maxLeftSlide = backgroundBitmap.getWidth() - slideButtonBitmap.getWidth();
// left_slide的范围为0=<left_slide<=maxLeftSlide
if (left_slide > maxLeftSlide) {
left_slide = maxLeftSlide;
currentState = true;
} else if (left_slide < 0) {
left_slide = 0;
currentState = false;
}
invalidate();
}
}
来源:https://www.cnblogs.com/FlySheep/p/3938776.html