}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setStrokeWidth(borderWidth);
paint.setStyle(Paint.Style.FILL);
//绘制白色背景
paint.setColor(background);
drawRoundRect(canvas,
left, top, right, bottom,
viewRadius, paint);
//绘制关闭状态的边框
paint.setStyle(Paint.Style.STROKE);
paint.setColor(uncheckColor);
drawRoundRect(canvas,
left, top, right, bottom,
viewRadius, paint);
//绘制小圆圈
if(showIndicator){
drawUncheckIndicator(canvas);
}
//绘制开启背景色
float des = viewState.radius * .5f;//[0-backgroundRadius*0.5f]
paint.setStyle(Paint.Style.STROKE);
paint.setColor(viewState.checkStateColor);
paint.setStrokeWidth(borderWidth + des * 2f);
drawRoundRect(canvas,
left + des, top + des, right - des, bottom - des,
viewRadius, paint);
//绘制按钮左边绿色长条遮挡
paint.setStyle(Paint.Style.FILL);
paint.setStrokeWidth(1);
drawArc(canvas,
left, top,
left + 2 * viewRadius, top + 2 * viewRadius,
90, 180, paint);
canvas.drawRect(
left + viewRadius, top,
viewState.buttonX, top + 2 * viewRadius,
paint);
//绘制小线条
if(showIndicator){
drawCheckedIndicator(canvas);
}
//绘制按钮
drawButton(canvas, viewState.buttonX, centerY);
}
/**
-
绘制选中状态指示器
-
@param canvas
*/
protected void drawCheckedIndicator(Canvas canvas) {
drawCheckedIndicator(canvas,
viewState.checkedLineColor,
checkLineWidth,
left + viewRadius - checkedLineOffsetX, centerY - checkLineLength,
left + viewRadius - checkedLineOffsetY, centerY + checkLineLength,
paint);
}
/**
-
绘制选中状态指示器
-
@param canvas
-
@param color
-
@param lineWidth
-
@param sx
-
@param sy
-
@param ex
-
@param ey
-
@param paint
*/
protected void drawCheckedIndicator(Canvas canvas,
int color,
float lineWidth,
float sx, float sy, float ex, float ey,
Paint paint) {
paint.setStyle(Paint.Style.STROKE);
paint.setColor(color);
paint.setStrokeWidth(lineWidth);
canvas.drawLine(
sx, sy, ex, ey,
paint);
}
/**
-
绘制关闭状态指示器
-
@param canvas
*/
private void drawUncheckIndicator(Canvas canvas) {
drawUncheckIndicator(canvas,
uncheckCircleColor,
uncheckCircleWidth,
right - uncheckCircleOffsetX, centerY,
uncheckCircleRadius,
paint);
}
/**
-
绘制关闭状态指示器
-
@param canvas
-
@param color
-
@param lineWidth
-
@param centerX
-
@param centerY
-
@param radius
-
@param paint
*/
protected void drawUncheckIndicator(Canvas canvas,
int color,
float lineWidth,
float centerX, float centerY,
float radius,
Paint paint) {
paint.setStyle(Paint.Style.STROKE);
paint.setColor(color);
paint.setStrokeWidth(lineWidth);
canvas.drawCircle(centerX, centerY, radius, paint);
}
/**
-
@param canvas
-
@param left
-
@param top
-
@param right
-
@param bottom
-
@param startAngle
-
@param sweepAngle
-
@param paint
*/
private void drawArc(Canvas canvas,
float left, float top,
float right, float bottom,
float startAngle, float sweepAngle,
Paint paint){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
canvas.drawArc(left, top, right, bottom,
startAngle, sweepAngle, true, paint);
}else{
rect.set(left, top, right, bottom);
canvas.drawArc(rect,
startAngle, sweepAngle, true, paint);
}
}
/**
-
@param canvas
-
@param left
-
@param top
-
@param right
-
@param bottom
-
@param backgroundRadius
-
@param paint
*/
private void drawRoundRect(Canvas canvas,
float left, float top,
float right, float bottom,
float backgroundRadius,
Paint paint){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
canvas.drawRoundRect(left, top, right, bottom,
backgroundRadius, backgroundRadius, paint);
}else{
rect.set(left, top, right, bottom);
canvas.drawRoundRect(rect,
backgroundRadius, backgroundRadius, paint);
}
}
/**
-
@param canvas
-
@param x px
-
@param y px
*/
private void drawButton(Canvas canvas, float x, float y) {
canvas.drawCircle(x, y, buttonRadius, buttonPaint);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(1);
paint.setColor(0XffDDDDDD);
canvas.drawCircle(x, y, buttonRadius, paint);
}
@Override
public void setChecked(boolean checked) {
if(checked == isChecked()){
postInvalidate();
return;
}
toggle(enableEffect, false);
}
@Override
public boolean isChecked() {
return isChecked;
}
@Override
public void toggle() {
toggle(true);
}
/**
-
切换状态
-
@param animate
*/
public void toggle(boolean animate) {
toggle(animate, true);
}
private void toggle(boolean animate, boolean broadcast) {
if(!isEnabled()){return;}
if(isEventBroadcast){
throw new RuntimeException(“should NOT switch the state in method: [onCheckedChanged]!”);
}
if(!isUiInited){
isChecked = !isChecked;
if(broadcast){
broadcastEvent();
}
return;
}
if(valueAnimator.isRunning()){
valueAnimator.cancel();
}
if(!enableEffect || !animate){
isChecked = !isChecked;
if(isChecked()){
setCheckedViewState(viewState);
}else{
setUncheckViewState(viewState);
}
postInvalidate();
if(broadcast){
broadcastEvent();
}
return;
}
animateState = ANIMATE_STATE_SWITCH;
beforeState.copy(viewState);
if(isChecked()){
//切换到unchecked
setUncheckViewState(afterState);
}else{
setCheckedViewState(afterState);
}
valueAnimator.start();
}
/**
*/
private void broadcastEvent() {
if(onCheckedChangeListener != null){
isEventBroadcast = true;
onCheckedChangeListener.onCheckedChanged(this, isChecked());
}
isEventBroadcast = false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if(!isEnabled()){return false;}
int actionMasked = event.getActionMasked();
switch (actionMasked){
case MotionEvent.ACTION_DOWN:{
isTouchingDown = true;
touchDownTime = System.currentTimeMillis();
//取消准备进入拖动状态
removeCallbacks(postPendingDrag);
//预设100ms进入拖动状态
postDelayed(postPendingDrag, 100);
break;
}
case MotionEvent.ACTION_MOVE:{
float eventX = event.getX();
if(isPendingDragState()){
//在准备进入拖动状态过程中,可以拖动按钮位置
float fraction = eventX / getWidth();
fraction = Math.max(0f, Math.min(1f, fraction));
viewState.buttonX = buttonMinX
- (buttonMaxX - buttonMinX)
- fraction;
}else if(isDragState()){
//拖动按钮位置,同时改变对应的背景颜色
float fraction = eventX / getWidth();
fraction = Math.max(0f, Math.min(1f, fraction));
viewState.buttonX = buttonMinX
- (buttonMaxX - buttonMinX)
- fraction;
viewState.checkStateColor = (int) argbEvaluator.evaluate(
fraction,
uncheckColor,
checkedColor
);
postInvalidate();
}
break;
}
case MotionEvent.ACTION_UP:{
isTouchingDown = false;
//取消准备进入拖动状态
removeCallbacks(postPendingDrag);
if(System.currentTimeMillis() - touchDownTime <= 300){
//点击时间小于300ms,认为是点击操作
toggle();
}else if(isDragState()){
//在拖动状态,计算按钮位置,设置是否切换状态
float eventX = event.getX();
float fraction = eventX / getWidth();
fraction = Math.max(0f, Math.min(1f, fraction));
boolean newCheck = fraction > .5f;
if(newCheck == isChecked()){
pendingCancelDragState();
}else{
isChecked = newCheck;
pendingSettleState();
}
}else if(isPendingDragState()){
//在准备进入拖动状态过程中,取消之,复位
pendingCancelDragState();
}
break;
}
case MotionEvent.ACTION_CANCEL:{
isTouchingDown = false;
removeCallbacks(postPendingDrag);
if(isPendingDragState()
|| isDragState()){
//复位
pendingCancelDragState();
}
break;
}
}
return true;
}
/**
-
是否在动画状态
-
@return
*/
private boolean isInAnimating(){
return animateState != ANIMATE_STATE_NONE;
}
/**
-
是否在进入拖动或离开拖动状态
-
@return
*/
private boolean isPendingDragState(){
return animateState == ANIMATE_STATE_PENDING_DRAG
|| animateState == ANIMATE_STATE_PENDING_RESET;
}
/**
-
是否在手指拖动状态
-
@return
*/
private boolean isDragState(){
return animateState == ANIMATE_STATE_DRAGING;
}
/**
-
设置是否启用阴影效果
-
@param shadowEffect true.启用
*/
public void setShadowEffect(boolean shadowEffect) {
if(this.shadowEffect == shadowEffect){return;}
this.shadowEffect = shadowEffect;
if(this.shadowEffect){
buttonPaint.setShadowLayer(
shadowRadius,
0, shadowOffset,
shadowColor);
}else{
buttonPaint.setShadowLayer(
0,
0, 0,
0);
}
}
public void setEnableEffect(boolean enable){
this.enableEffect = enable;
}
/**
- 开始进入拖动状态
*/
private void pendingDragState() {
if(isInAnimating()){return;}
if(!isTouchingDown){return;}
if(valueAnimator.isRunning()){
valueAnimator.cancel();
}
animateState = ANIMATE_STATE_PENDING_DRAG;
beforeState.copy(viewState);
afterState.copy(viewState);
if(isChecked()){
afterState.checkStateColor = checkedColor;
afterState.buttonX = buttonMaxX;
afterState.checkedLineColor = checkedColor;
}else{
afterState.checkStateColor = uncheckColor;
afterState.buttonX = buttonMinX;
afterState.radius = viewRadius;
}
valueAnimator.start();
}
/**
- 取消拖动状态
*/
private void pendingCancelDragState() {
if(isDragState() || isPendingDragState()){
if(valueAnimator.isRunning()){
valueAnimator.cancel();
}
animateState = ANIMATE_STATE_PENDING_RESET;
beforeState.copy(viewState);
if(isChecked()){
setCheckedViewState(afterState);
}else{
setUncheckViewState(afterState);<