这是我参与11月更文挑战的第24天,活动详情查看:2021最后一次更文挑战
前言
Android 开发系统自带很多常用的系统控件,文本的,图片的,按钮的,进度条的,下拉列表的等等,一些手机中比较常用的控件,Android系统都会提供,一般只要在原有的控件基础上做一些简单的修改,就可以实现开发中很多设计要求的图或者操作控件,但是我们不能用仅用Android自带的控件,我们也要学会通过学习Android的系统源码,了解view的绘制流程,去实现自己写一个View供我们自己使用,学以致用,才是学习的最终目的。
实现一个自定义切换按钮
类似这样的,支持开关,禁用等功能。
准备工作
想要实现上面UI给的设计图,首先需要把要实现的View所包含的元素了解清楚,切换按钮也就是开关按钮,有开有关,这个是必不可少的,开关也可以不让使用,所以还需要有一个禁用的状态,从图中可以看出,要绘制,首先要拆分,怎么拆分呢,首先是开按钮,可以拆成底色,然后还有个圆球,再就是外层的白色蒙层,然后关闭按钮,底色,圆球,白色蒙层,仔细看,外层还有个灰色的外框,统一一下,就是:
1.底色
2.圆球
3.白色蒙层
4.外层边框
初始化一些需要使用的元素
public class MySwitchButton extends View {
private int openColor = 0xFF1a81d1;//默认打开色值
private int closeColor = 0xFFD0D0D0;//默认关闭色值
private int strokeColor;//边框色值
private int strokeWidth;//边框宽度
private int strokeRound;//边框的圆角
private int switchWidth = 100;//开关宽度
private int switchHeight = 50;//开关高度
private int int rimSize = 3;//边缘间距
/****画笔****/
private Paint openPaint;//开启的画笔
private Paint closePaint;//关闭的画笔
private Paint paintCircle;//圆球画笔
/****形状****/
private Rect backRect;//背景的背景形状
private Rect frontRect;//阴影的形状
private RectF closeRect;//关闭的背景形状
private RectF lineCircleRect;//边框的形状
private RectF frontCircleRect;//圆球
private RectF backCircleRect;//阴影的形状
/****透明度****/
private int enableAlpha;//开启的透明度
private int disableAlpha;//关闭的透明度
private boolean enable = true;
public MySwitchButton(Context context) {
this(context, null);
}
public MySwitchButton(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MySwitchButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttrs(context, attrs);
}
/***
* 初始化属性配置
* @param context
* @param attrs
*/
protected void initAttrs(Context context, @Nullable AttributeSet attrs) {
openPaint = new Paint();
closePaint = new Paint();
paintCircle = new Paint();
openPaint.setAntiAlias(true);
closePaint.setAntiAlias(true);
paintCircle.setAntiAlias(true);
if (attrs != null) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MySwitchButton);
openColor = typedArray.getColor(R.styleable.MySwitchButton_switch_open_color, getResources().getColor(R.color.open_color_default));
closeColor = typedArray.getColor(R.styleable.MySwitchButton_switch_close_color, getResources().getColor(R.color.close_color_default));
enable = typedArray.getBoolean(R.styleable.MySwitchButton_switch_enable, true);
typedArray.recycle();
}
strokeColor = getContext().getResources().getColor(R.color.transparent_10);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = measureDimension(DEFAULT_WIDTH, widthMeasureSpec);
int height = measureDimension(DEFAULT_HEIGHT, heightMeasureSpec);
//如果设置的宽度小于高度,重置宽度为高度的2倍
if (shape == SHAPE_CIRCLE) {
if (width < height) width = height * 2;
}
setMeasuredDimension(width, height);
initDrawingVal();
}
/***
* 根据mode 重新赋值
* @param defaultSize
* @param measureSpec
* @return
*/
private int measureDimension(int defaultSize, int measureSpec) {
int result;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
result = defaultSize;
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
}
return result;
}
/***
* 绘制椭圆
*/
private void initDrawingVal() {
int width = getMeasuredWidth();
int height = getMeasuredHeight();
backCircleRect = new RectF();
frontCircleRect = new RectF();
frontRect = new Rect();
backRect = new Rect(0, 0, width, height);
closeRect = new RectF(0, 0, width, height);
lineCircleRect = new RectF(STROKE_SIZE, STROKE_SIZE, width - STROKE_SIZE, height - STROKE_SIZE);
if (isOpen) {
enableAlpha = 255;
} else {
enableAlpha = 0;
}
if (!enable) {
disableAlpha = 80;
}
}
}
复制代码
初始化工作差不多了,attrs文件,后面会补上,简单看下都是些基础的自定义view的通用初始化工作,再把外层的椭圆画完,基本的准备工作差不多了。后面会着重把绘制的主体实现,也就是onDraw()方法,onTouchEvent()事件的处理。