这是我参与11月更文挑战的第26天,活动详情查看:2021最后一次更文挑战
紧接着上一篇文章的内容,已经差不多了,主体的绘制和事件处理都已经做完,剩下的就是对这些的操作的实现和优化了,还有一些对外公开的接口,方法,设置参数等,已经一些数据的存储,恢复等
接下来就是一些设置类的方法了:
/***
* 获取状态
* @param state
*/
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (state instanceof Bundle) {
Bundle bundle = (Bundle) state;
this.isOpen = bundle.getBoolean("isOpen");
state = bundle.getParcelable("instanceState");
}
super.onRestoreInstanceState(state);
}
/***
* 保存状态
*/
@Override
protected Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putParcelable("instanceState", super.onSaveInstanceState());
bundle.putBoolean("isOpen", this.isOpen);
return bundle;
}
/***
* 设置是否可用
* @param enable
*/
public void setEnable(boolean enable) {
this.enable = enable;
initDrawingVal();
invalidateView();
}
/***
* 设置是否支持滑动
* @param slideable
*/
public void setSlideable(boolean slideable) {
this.slideable = slideable;
}
public boolean isEnable() {
return enable;
}
public int getEnableAlpha() {
return enableAlpha;
}
public void setEnableAlpha(int enableAlpha) {
this.enableAlpha = enableAlpha;
}
public int getDisableAlpha() {
return disableAlpha;
}
public void setDisableAlpha(int disableAlpha) {
this.disableAlpha = disableAlpha;
}
public boolean isOpen() {
return isOpen;
}
/***
* 设置是否默认开启
* @param isOpen
*/
public void setOpen(boolean isOpen) {
setOpen(isOpen, false);
}
public void setOpen(boolean isOpen, boolean invokListener) {
this.isOpen = isOpen;
initDrawingVal();
invalidateView();
if (invokListener && phSwitchButtonListener != null)
phSwitchButtonListener.onStatusChanged(this, isOpen);
}
public int getOpenColor() {
return openColor;
}
public void setOpenColor(int openColor) {
this.openColor = openColor;
}
public int getCloseColor() {
return closeColor;
}
protected void setCloseColor(int closeColor) {
this.closeColor = closeColor;
}
根据业务需要,开放对外的接口,当然也可以设置开关的形状,矩形的,圆形的,逻辑都一样,就是添加一个判断,注释都有写,稍后会把完整的代码贴出来。
总结
自定义view就是需要细致,逻辑清楚,先大体绘制框架,然后进行微调,遇到问题,仔细的调试,修改设置属性,就可以慢慢完整的把功能实现,所有的逻辑都是通过一步步粗写,细调,慢慢堆砌出来的,日积月累,就形成了习惯,也就是我们说的经验。
下面把完整的代码贴出来
public class MySwitchButton extends View {
/****圆形形状****/
public static final int SHAPE_CIRCLE = 1;
/****矩形形状****/
public static final int SHAPE_RECT = 2;
private static final int SHAPE_DEFAULT = 1;
private int openColor = 0xFF1a81d1;//默认打开色值
private int closeColor = 0xFFD0D0D0;//默认关闭色值
private int strokeColor;//边框色值
private int strokeWidth = 3;//边框宽度
private int strokeRound = 6;//边框的圆角
private int switchWidth = 100;//开关宽度
private int switchHeight = 50;//开关高度
private int rimSize = 3;//边缘间距
/****是否默认开启****/
private boolean isOpen;
/****形状****/
private int shape;
/****画笔****/
private Paint openPaint;
private Paint closePaint;
private Paint paintCircle;
/****形状****/
private Rect backRect;
private Rect frontRect;
private RectF frontCircleRect;
private RectF backCircleRect;
private RectF closeRect;
private RectF lineCircleRect;
/****透明度****/
private int enableAlpha;
private int disableAlpha;
private int maxLeft;
private int minLeft;
private int frontRectLeft;
private int frontRectLeftBegin = rimSize;
private int eventStartX;
private int eventLastX;
private int diffX = 0;
private boolean slideable = true;
/****切换回调****/
private MySwitchButtonListener mySwitchButtonListener;
private boolean enable = true;
/***
* 切换接口类
*/
public interface MySwitchButtonListener {
void onStatusChanged(MySwitchButton view, boolean isOpen);
}
public MySwitchButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MySwitchButton(Context context) {
this(context, null);
}
public MySwitchButton(Context context, 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);
shape = typedArray.getInt(R.styleable.PHSwitchButton_switch_shape, SHAPE_DEFAULT);
slideable = typedArray.getBoolean(R.styleable.PHSwitchButton_switch_slideable, true);
openColor = typedArray.getColor(R.styleable.MySwitchButton_switch_open_color,openColor);
closeColor = typedArray.getColor(R.styleable.MySwitchButton_switch_close_color, closeColor);
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(strokeWidth, widthMeasureSpec);
int height = measureDimension(switchHeight, heightMeasureSpec);
//如果设置的宽度小于高度,重置宽度为高度的2倍
if (shape == SHAPE_CIRCLE) {
if (width < height) width = height * 2;
}
setMeasuredDimension(width, height);
initDrawingVal();
}
/***
* 绘制椭圆
*/
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(rimSize, rimSize, width - rimSize, height - rimSize);
lineCircleRect = new RectF(strokeWidth, strokeWidth, width - strokeWidth, height - strokeWidth);
minLeft = rimSize;
if (shape == SHAPE_RECT)
maxLeft = width / 2;
else
maxLeft = width - (height - 2 * rimSize) - rimSize;
if (isOpen) {
frontRectLeft = maxLeft;
enableAlpha = 255;
} else {
frontRectLeft = rimSize;
enableAlpha = 0;
}
if (!enable) {
slideable = false;
disableAlpha = 80;
}
frontRectLeftBegin = frontRectLeft;
}
/***
* 根据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;
}
@Override
protected void onDraw(Canvas canvas) {
if (shape == SHAPE_RECT) {
closePaint.setColor(closeColor);
canvas.drawRect(backRect, closePaint);
openPaint.setColor(openColor);
openPaint.setAlpha(enableAlpha);
canvas.drawRect(backRect, openPaint);
openPaint.setColor(openColor);
openPaint.setAlpha(enableAlpha);
canvas.drawRect(backRect, openPaint);
frontRect.set(frontRectLeft, rimSize, frontRectLeft + getMeasuredWidth() / 2 - rimSize, getMeasuredHeight() - rimSize);
paintCircle.setColor(Color.WHITE);
paintCircle.setShadowLayer(strokeRound, 0, 0, strokeColor);
canvas.drawRect(frontRect, paintCircle);
setLayerType(LAYER_TYPE_SOFTWARE, null);
} else {
int radius;
radius = backRect.height() / 2;
//画关闭
if (enable) {
//画关闭背景外框
closePaint.setColor(strokeColor);
closePaint.setStyle(Paint.Style.STROKE);
closePaint.setStrokeWidth(strokeWidth);
canvas.drawRoundRect(lineCircleRect, radius, radius, closePaint);
//画关闭背景
closePaint.setColor(closeColor);
closePaint.setStyle(Paint.Style.FILL);
canvas.drawRoundRect(closeRect, radius, radius, closePaint);
} else {
//画关闭背景外框
closePaint.setColor(strokeColor);
closePaint.setStyle(Paint.Style.STROKE);
closePaint.setStrokeWidth(strokeWidth);
canvas.drawRoundRect(lineCircleRect, radius, radius, closePaint);
//画关闭背景
closePaint.setColor(closeColor);
closePaint.setStyle(Paint.Style.FILL);
canvas.drawRoundRect(closeRect, radius, radius, closePaint);
//阴影
closePaint.setColor(Color.WHITE);
closePaint.setStyle(Paint.Style.FILL);
backCircleRect.set(backRect);
closePaint.setAlpha(disableAlpha);
canvas.drawRoundRect(backCircleRect, radius, radius, closePaint);
}
//画开启
openPaint.setColor(openColor);
openPaint.setAlpha(enableAlpha);
backCircleRect.set(backRect);
canvas.drawRoundRect(backCircleRect, radius, radius, openPaint);
//画不可用
openPaint.setColor(Color.WHITE);
openPaint.setAlpha(disableAlpha);
canvas.drawRoundRect(backCircleRect, radius, radius, openPaint);
//画小圆
frontRect.set(frontRectLeft, rimSize, frontRectLeft + backRect.height() - 2 * rimSize, backRect.height() - rimSize);
frontCircleRect.set(frontRect);
paintCircle.setColor(Color.WHITE);
paintCircle.setShadowLayer(strokeRound, 0, 0, strokeColor);
canvas.drawRoundRect(frontCircleRect, radius, radius, paintCircle);
setLayerType(LAYER_TYPE_SOFTWARE, null);
}
}
private boolean isActionMove = false;
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!enable)
return super.onTouchEvent(event);
int action = MotionEventCompat.getActionMasked(event);
switch (action) {
case MotionEvent.ACTION_DOWN:
eventStartX = (int) event.getRawX();
break;
case MotionEvent.ACTION_MOVE:
if (slideable) {
eventLastX = (int) event.getRawX();
diffX = eventLastX - eventStartX;
int tempX = diffX + frontRectLeftBegin;
tempX = (tempX > maxLeft ? maxLeft : tempX);
tempX = (tempX < minLeft ? minLeft : tempX);
if (tempX >= minLeft && tempX <= maxLeft) {
frontRectLeft = tempX;
enableAlpha = (int) (255 * (float) tempX / (float) maxLeft);
isActionMove = true;
invalidateView();
}
}
break;
case MotionEvent.ACTION_UP:
sliderMove(event);
break;
case MotionEvent.ACTION_CANCEL:
if (isActionMove) {
sliderMove(event);
}
Log.e("onTouchEvent:", "ACTION_CANCEL");
break;
default:
break;
}
return true;
}
/***
* 执行滑动
* @param event
*/
private void sliderMove(MotionEvent event) {
int wholeX = (int) (event.getRawX() - eventStartX);
frontRectLeftBegin = frontRectLeft;
boolean toRight;
toRight = (frontRectLeftBegin > maxLeft / 2 ? true : false);
if (Math.abs(wholeX) < 3) {
toRight = !toRight;
}
moveToDest(toRight);
}
/**
* 重新绘制
*/
private void invalidateView() {
if (Looper.getMainLooper() == Looper.myLooper()) {
invalidate();
} else {
postInvalidate();
}
}
/***
* 设置监听
* @param listener
*/
public void setPHSwitchButtonListener(MySwitchButtonListener listener) {
this.mySwitchButtonListener = listener;
}
public int getOpenColor() {
return openColor;
}
public void setOpenColor(int openColor) {
this.openColor = openColor;
}
public int getCloseColor() {
return closeColor;
}
protected void setCloseColor(int closeColor) {
this.closeColor = closeColor;
}
/***
* 切换操作
* @param toRight
*/
public void moveToDest(final boolean toRight) {
/****切换动画****/
ValueAnimator toDestAnim = ValueAnimator.ofInt(frontRectLeft, toRight ? maxLeft : minLeft);
toDestAnim.setDuration(300);
toDestAnim.setInterpolator(new AccelerateDecelerateInterpolator());
toDestAnim.start();
toDestAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
setLayerType(LAYER_TYPE_NONE, null);
frontRectLeft = (Integer) animation.getAnimatedValue();
enableAlpha = (int) (255 * (float) frontRectLeft / (float) maxLeft);
invalidateView();
}
});
toDestAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (toRight) {
isOpen = true;
frontRectLeftBegin = maxLeft;
enableAlpha = 255;
} else {
isOpen = false;
frontRectLeftBegin = minLeft;
enableAlpha = 0;
}
if (mySwitchButtonListener != null)
mySwitchButtonListener.onStatusChanged(MySwitchButton.this, isOpen);
}
});
}
public boolean isOpen() {
return isOpen;
}
/***
* 设置是否默认开启
* @param isOpen
*/
public void setOpen(boolean isOpen) {
setOpen(isOpen, false);
}
public void setOpen(boolean isOpen, boolean invokListener) {
this.isOpen = isOpen;
initDrawingVal();
invalidateView();
if (invokListener && mySwitchButtonListener != null)
mySwitchButtonListener.onStatusChanged(this, isOpen);
}
/***
* 设置形状
* @param shapeType
*/
public void setShapeType(int shapeType) {
this.shape = shapeType;
}
/***
* 设置是否支持滑动
* @param slideable
*/
public void setSlideable(boolean slideable) {
this.slideable = slideable;
}
public boolean isEnable() {
return enable;
}
public int getEnableAlpha() {
return enableAlpha;
}
public void setEnableAlpha(int enableAlpha) {
this.enableAlpha = enableAlpha;
}
public int getDisableAlpha() {
return disableAlpha;
}
public void setDisableAlpha(int disableAlpha) {
this.disableAlpha = disableAlpha;
}
/***
* 设置是否可用
* @param enable
*/
public void setEnable(boolean enable) {
this.enable = enable;
initDrawingVal();
invalidateView();
}
/***
* 获取状态
* @param state
*/
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (state instanceof Bundle) {
Bundle bundle = (Bundle) state;
this.isOpen = bundle.getBoolean("isOpen");
state = bundle.getParcelable("instanceState");
}
super.onRestoreInstanceState(state);
}
/***
* 保存状态
*/
@Override
protected Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putParcelable("instanceState", super.onSaveInstanceState());
bundle.putBoolean("isOpen", this.isOpen);
return bundle;
}
}
资源文件:
<declare-styleable name="MySwitchButton">
<attr name="switch_shape" format="enum">
<enum name="CIRCLE" value="1" />
<enum name="RECT" value="2" />
</attr>
<attr name="switch_slideable" format="boolean" />
<attr name="switch_open" format="boolean" />
<attr name="switch_open_color" format="color" />
<attr name="switch_close_color" format="color" />
<attr name="switch_enable" format="boolean" />
</declare-styleable>