使用步驟:
1,把自定義SwitchButton放進(jìn)去
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Build;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Checkable;
public class SwitchButtonextends Viewimplements Checkable {
private static final int DEFAULT_WIDTH =dp2pxInt(58);
? ? private static final int DEFAULT_HEIGHT =dp2pxInt(36);
? ? /**
* 動(dòng)畫狀態(tài):
* 1.靜止
* 2.進(jìn)入拖動(dòng)
* 3.處于拖動(dòng)
* 4.拖動(dòng)-復(fù)位
* 5.拖動(dòng)-切換
* 6.點(diǎn)擊切換
* **/
? ? private final int ANIMATE_STATE_NONE =0;
? ? private final int ANIMATE_STATE_PENDING_DRAG =1;
? ? private final int ANIMATE_STATE_DRAGING =2;
? ? private final int ANIMATE_STATE_PENDING_RESET =3;
? ? private final int ANIMATE_STATE_PENDING_SETTLE =4;
? ? private final int ANIMATE_STATE_SWITCH =5;
? ? public SwitchButton(Context context) {
super(context);
? ? ? ? init(context, null);
? ? }
public SwitchButton(Context context, AttributeSet attrs) {
super(context, attrs);
? ? ? ? init(context, attrs);
? ? }
public SwitchButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
? ? ? ? init(context, attrs);
? ? }
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public SwitchButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
? ? ? ? init(context, attrs);
? ? }
@Override
? ? public final void setPadding(int left, int top, int right, int bottom) {
super.setPadding(0, 0, 0, 0);
? ? }
/**
* 初始化參數(shù)
*/
? ? private void init(Context context, AttributeSet attrs) {
TypedArray typedArray =null;
? ? ? ? if(attrs !=null){
typedArray = context.obtainStyledAttributes(attrs, R.styleable.SwitchButton);
? ? ? ? }
shadowEffect =optBoolean(typedArray,
? ? ? ? ? ? ? ? R.styleable.SwitchButton_sb_shadow_effect,
? ? ? ? ? ? ? ? true);
? ? ? ? uncheckCircleColor =optColor(typedArray,
? ? ? ? ? ? ? ? R.styleable.SwitchButton_sb_uncheckcircle_color,
? ? ? ? ? ? ? ? 0XffAAAAAA);//0XffAAAAAA;
? ? ? ? uncheckCircleWidth =optPixelSize(typedArray,
? ? ? ? ? ? ? ? R.styleable.SwitchButton_sb_uncheckcircle_width,
? ? ? ? ? ? ? ? dp2pxInt(1.5f));//dp2pxInt(1.5f);
? ? ? ? uncheckCircleOffsetX =dp2px(10);
? ? ? ? uncheckCircleRadius =optPixelSize(typedArray,
? ? ? ? ? ? ? ? R.styleable.SwitchButton_sb_uncheckcircle_radius,
? ? ? ? ? ? ? ? dp2px(4));//dp2px(4);
? ? ? ? checkedLineOffsetX =dp2px(4);
? ? ? ? checkedLineOffsetY =dp2px(4);
? ? ? ? shadowRadius =optPixelSize(typedArray,
? ? ? ? ? ? ? ? R.styleable.SwitchButton_sb_shadow_radius,
? ? ? ? ? ? ? ? dp2pxInt(2.5f));//dp2pxInt(2.5f);
? ? ? ? shadowOffset =optPixelSize(typedArray,
? ? ? ? ? ? ? ? R.styleable.SwitchButton_sb_shadow_offset,
? ? ? ? ? ? ? ? dp2pxInt(1.5f));//dp2pxInt(1.5f);
? ? ? ? shadowColor =optColor(typedArray,
? ? ? ? ? ? ? ? R.styleable.SwitchButton_sb_shadow_color,
? ? ? ? ? ? ? ? 0X33000000);//0X33000000;
? ? ? ? uncheckColor =optColor(typedArray,
? ? ? ? ? ? ? ? R.styleable.SwitchButton_sb_uncheck_color,
? ? ? ? ? ? ? ? 0XffDDDDDD);//0XffDDDDDD;
? ? ? ? checkedColor =optColor(typedArray,
? ? ? ? ? ? ? ? R.styleable.SwitchButton_sb_checked_color,
? ? ? ? ? ? ? ? 0Xff51d367);//0Xff51d367;
? ? ? ? borderWidth =optPixelSize(typedArray,
? ? ? ? ? ? ? ? R.styleable.SwitchButton_sb_border_width,
? ? ? ? ? ? ? ? dp2pxInt(1));//dp2pxInt(1);
? ? ? ? checkLineColor =optColor(typedArray,
? ? ? ? ? ? ? ? R.styleable.SwitchButton_sb_checkline_color,
? ? ? ? ? ? ? ? Color.WHITE);//Color.WHITE;
? ? ? ? checkLineWidth =optPixelSize(typedArray,
? ? ? ? ? ? ? ? R.styleable.SwitchButton_sb_checkline_width,
? ? ? ? ? ? ? ? dp2pxInt(1f));//dp2pxInt(1.0f);
? ? ? ? checkLineLength =dp2px(6);
? ? ? ? int buttonColor =optColor(typedArray,
? ? ? ? ? ? ? ? R.styleable.SwitchButton_sb_button_color,
? ? ? ? ? ? ? ? Color.WHITE);//Color.WHITE;
? ? ? ? int effectDuration =optInt(typedArray,
? ? ? ? ? ? ? ? R.styleable.SwitchButton_sb_effect_duration,
? ? ? ? ? ? ? ? 300);//300;
? ? ? ? isChecked =optBoolean(typedArray,
? ? ? ? ? ? ? ? R.styleable.SwitchButton_sb_checked,
? ? ? ? ? ? ? ? false);
? ? ? ? showIndicator =optBoolean(typedArray,
? ? ? ? ? ? ? ? R.styleable.SwitchButton_sb_show_indicator,
? ? ? ? ? ? ? ? true);
? ? ? ? background =optColor(typedArray,
? ? ? ? ? ? ? ? R.styleable.SwitchButton_sb_background,
? ? ? ? ? ? ? ? Color.WHITE);//Color.WHITE;
? ? ? ? enableEffect =optBoolean(typedArray,
? ? ? ? ? ? ? ? R.styleable.SwitchButton_sb_enable_effect,
? ? ? ? ? ? ? ? true);
? ? ? ? if(typedArray !=null){
typedArray.recycle();
? ? ? ? }
paint =new Paint(Paint.ANTI_ALIAS_FLAG);
? ? ? ? buttonPaint =new Paint(Paint.ANTI_ALIAS_FLAG);
? ? ? ? buttonPaint.setColor(buttonColor);
? ? ? ? if(shadowEffect){
buttonPaint.setShadowLayer(
shadowRadius,
? ? ? ? ? ? ? ? ? ? 0, shadowOffset,
? ? ? ? ? ? ? ? ? ? shadowColor);
? ? ? ? }
viewState =new ViewState();
? ? ? ? beforeState =new ViewState();
? ? ? ? afterState =new ViewState();
? ? ? ? valueAnimator = ValueAnimator.ofFloat(0f, 1f);
? ? ? ? valueAnimator.setDuration(effectDuration);
? ? ? ? valueAnimator.setRepeatCount(0);
? ? ? ? valueAnimator.addUpdateListener(animatorUpdateListener);
? ? ? ? valueAnimator.addListener(animatorListener);
? ? ? ? super.setClickable(true);
? ? ? ? this.setPadding(0, 0, 0, 0);
? ? ? ? if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
setLayerType(LAYER_TYPE_SOFTWARE, null);
? ? ? ? }
}
@Override
? ? protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
? ? ? ? final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
? ? ? ? if(widthMode == MeasureSpec.UNSPECIFIED
? ? ? ? ? ? ? ? || widthMode == MeasureSpec.AT_MOST){
widthMeasureSpec = MeasureSpec.makeMeasureSpec(DEFAULT_WIDTH, MeasureSpec.EXACTLY);
? ? ? ? }
if(heightMode == MeasureSpec.UNSPECIFIED
? ? ? ? ? ? ? ? || heightMode == MeasureSpec.AT_MOST){
heightMeasureSpec = MeasureSpec.makeMeasureSpec(DEFAULT_HEIGHT, MeasureSpec.EXACTLY);
? ? ? ? }
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
? ? }
@Override
? ? protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
? ? ? ? float viewPadding = Math.max(shadowRadius +shadowOffset, borderWidth);
? ? ? ? height = h - viewPadding - viewPadding;
? ? ? ? width = w - viewPadding - viewPadding;
? ? ? ? viewRadius =height *.5f;
? ? ? ? buttonRadius =viewRadius -borderWidth;
? ? ? ? left = viewPadding;
? ? ? ? top = viewPadding;
? ? ? ? right = w - viewPadding;
? ? ? ? bottom = h - viewPadding;
? ? ? ? centerX = (left +right) *.5f;
? ? ? ? centerY = (top +bottom) *.5f;
? ? ? ? buttonMinX =left +viewRadius;
? ? ? ? buttonMaxX =right -viewRadius;
? ? ? ? if(isChecked()){
setCheckedViewState(viewState);
? ? ? ? }else{
setUncheckViewState(viewState);
? ? ? ? }
isUiInited =true;
? ? ? ? postInvalidate();
? ? }
/**
? ? * @param viewState
? ? */
? ? private void setUncheckViewState(ViewState viewState){
viewState.radius =0;
? ? ? ? viewState.checkStateColor =uncheckColor;
? ? ? ? viewState.checkedLineColor = Color.TRANSPARENT;
? ? ? ? viewState.buttonX =buttonMinX;
? ? }
/**
? ? * @param viewState
? ? */
? ? private void setCheckedViewState(ViewState viewState){
viewState.radius =viewRadius;
? ? ? ? viewState.checkStateColor =checkedColor;
? ? ? ? viewState.checkedLineColor =checkLineColor;
? ? ? ? viewState.buttonX =buttonMaxX;
? ? }
@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);
? ? ? ? //繪制關(guān)閉狀態(tài)的邊框
? ? ? ? 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);
? ? }
/**
* 繪制選中狀態(tài)指示器
? ? * @param canvas
? ? */
? ? protected void drawCheckedIndicator(Canvas canvas) {
drawCheckedIndicator(canvas,
? ? ? ? ? ? ? ? viewState.checkedLineColor,
? ? ? ? ? ? ? ? checkLineWidth,
? ? ? ? ? ? ? ? left +viewRadius -checkedLineOffsetX, centerY -checkLineLength,
? ? ? ? ? ? ? ? left +viewRadius -checkedLineOffsetY, centerY +checkLineLength,
? ? ? ? ? ? ? ? paint);
? ? }
/**
* 繪制選中狀態(tài)指示器
? ? * @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);
? ? }
/**
* 繪制關(guān)閉狀態(tài)指示器
? ? * @param canvas
? ? */
? ? private void drawUncheckIndicator(Canvas canvas) {
drawUncheckIndicator(canvas,
? ? ? ? ? ? ? ? uncheckCircleColor,
? ? ? ? ? ? ? ? uncheckCircleWidth,
? ? ? ? ? ? ? ? right -uncheckCircleOffsetX, centerY,
? ? ? ? ? ? ? ? uncheckCircleRadius,
? ? ? ? ? ? ? ? paint);
? ? }
/**
* 繪制關(guān)閉狀態(tài)指示器
? ? * @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);
? ? }
/**
* 切換狀態(tài)
? ? * @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();
? ? ? ? ? ? ? ? //取消準(zhǔn)備進(jìn)入拖動(dòng)狀態(tài)
? ? ? ? ? ? ? ? removeCallbacks(postPendingDrag);
? ? ? ? ? ? ? ? //預(yù)設(shè)100ms進(jìn)入拖動(dòng)狀態(tài)
? ? ? ? ? ? ? ? postDelayed(postPendingDrag, 100);
break;
? ? ? ? ? ? }
case MotionEvent.ACTION_MOVE:{
float eventX = event.getX();
? ? ? ? ? ? ? ? if(isPendingDragState()){
//在準(zhǔn)備進(jìn)入拖動(dòng)狀態(tài)過程中驾讲,可以拖動(dòng)按鈕位置
? ? ? ? ? ? ? ? ? ? float fraction = eventX / getWidth();
? ? ? ? ? ? ? ? ? ? fraction = Math.max(0f, Math.min(1f, fraction));
? ? ? ? ? ? ? ? ? ? viewState.buttonX =buttonMinX
? ? ? ? ? ? ? ? ? ? ? ? ? ? + (buttonMaxX -buttonMinX)
* fraction;
? ? ? ? ? ? ? ? }else if(isDragState()){
//拖動(dòng)按鈕位置蚊伞,同時(shí)改變對應(yīng)的背景顏色
? ? ? ? ? ? ? ? ? ? float fraction = eventX / getWidth();
? ? ? ? ? ? ? ? ? ? fraction = Math.max(0f, Math.min(1f, fraction));
? ? ? ? ? ? ? ? ? ? viewState.buttonX =buttonMinX
? ? ? ? ? ? ? ? ? ? ? ? ? ? + (buttonMaxX -buttonMinX)
* fraction;
? ? ? ? ? ? ? ? ? ? viewState.checkStateColor = (Integer)argbEvaluator.evaluate(
fraction,
? ? ? ? ? ? ? ? ? ? ? ? ? ? uncheckColor,
? ? ? ? ? ? ? ? ? ? ? ? ? ? checkedColor
? ? ? ? ? ? ? ? ? ? );
? ? ? ? ? ? ? ? ? ? postInvalidate();
? ? ? ? ? ? ? ? }
break;
? ? ? ? ? ? }
case MotionEvent.ACTION_UP:{
isTouchingDown =false;
? ? ? ? ? ? ? ? //取消準(zhǔn)備進(jìn)入拖動(dòng)狀態(tài)
? ? ? ? ? ? ? ? removeCallbacks(postPendingDrag);
? ? ? ? ? ? ? ? if(System.currentTimeMillis() -touchDownTime <=300){
//點(diǎn)擊時(shí)間小于300ms,認(rèn)為是點(diǎn)擊操作
? ? ? ? ? ? ? ? ? ? toggle();
? ? ? ? ? ? ? ? }else if(isDragState()){
//在拖動(dòng)狀態(tài)吮铭,計(jì)算按鈕位置时迫,設(shè)置是否切換狀態(tài)
? ? ? ? ? ? ? ? ? ? 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()){
//在準(zhǔn)備進(jìn)入拖動(dòng)狀態(tài)過程中,取消之谓晌,復(fù)位
? ? ? ? ? ? ? ? ? ? pendingCancelDragState();
? ? ? ? ? ? ? ? }
break;
? ? ? ? ? ? }
case MotionEvent.ACTION_CANCEL:{
isTouchingDown =false;
? ? ? ? ? ? ? ? removeCallbacks(postPendingDrag);
? ? ? ? ? ? ? ? if(isPendingDragState()
|| isDragState()){
//復(fù)位
? ? ? ? ? ? ? ? ? ? pendingCancelDragState();
? ? ? ? ? ? ? ? }
break;
? ? ? ? ? ? }
}
return true;
? ? }
/**
* 是否在動(dòng)畫狀態(tài)
? ? * @return
? ? */
? ? private boolean isInAnimating(){
return animateState !=ANIMATE_STATE_NONE;
? ? }
/**
* 是否在進(jìn)入拖動(dòng)或離開拖動(dòng)狀態(tài)
? ? * @return
? ? */
? ? private boolean isPendingDragState(){
return animateState ==ANIMATE_STATE_PENDING_DRAG
? ? ? ? ? ? ? ? ||animateState ==ANIMATE_STATE_PENDING_RESET;
? ? }
/**
* 是否在手指拖動(dòng)狀態(tài)
? ? * @return
? ? */
? ? private boolean isDragState(){
return animateState ==ANIMATE_STATE_DRAGING;
? ? }
/**
* 設(shè)置是否啟用陰影效果
? ? * @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;
? ? }
/**
* 開始進(jìn)入拖動(dòng)狀態(tài)
*/
? ? 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();
? ? }
/**
* 取消拖動(dòng)狀態(tài)
*/
? ? 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);
? ? ? ? ? ? }
valueAnimator.start();
? ? ? ? }
}
/**
* 動(dòng)畫-設(shè)置新的狀態(tài)
*/
? ? private void pendingSettleState() {
if(valueAnimator.isRunning()){
valueAnimator.cancel();
? ? ? ? }
animateState =ANIMATE_STATE_PENDING_SETTLE;
? ? ? ? beforeState.copy(viewState);
? ? ? ? if(isChecked()){
setCheckedViewState(afterState);
? ? ? ? }else{
setUncheckViewState(afterState);
? ? ? ? }
valueAnimator.start();
? ? }
@Override
? ? public final void setOnClickListener(OnClickListener l) {}
@Override
? ? public final void setOnLongClickListener(OnLongClickListener l) {}
public void setOnCheckedChangeListener(OnCheckedChangeListener l){
onCheckedChangeListener = l;
? ? }
public interface OnCheckedChangeListener{
void onCheckedChanged(SwitchButton view, boolean isChecked);
? ? }
/*******************************************************/
? ? private static float dp2px(float dp){
Resources r = Resources.getSystem();
? ? ? ? return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics());
? ? }
private static int dp2pxInt(float dp){
return (int)dp2px(dp);
? ? }
private static int optInt(TypedArray typedArray,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int index,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int def) {
if(typedArray ==null){return def;}
return typedArray.getInt(index, def);
? ? }
private static float optPixelSize(TypedArray typedArray,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int index,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? float def) {
if(typedArray ==null){return def;}
return typedArray.getDimension(index, def);
? ? }
private static int optPixelSize(TypedArray typedArray,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int index,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int def) {
if(typedArray ==null){return def;}
return typedArray.getDimensionPixelOffset(index, def);
? ? }
private static int optColor(TypedArray typedArray,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int index,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int def) {
if(typedArray ==null){return def;}
return typedArray.getColor(index, def);
? ? }
private static boolean optBoolean(TypedArray typedArray,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int index,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? boolean def) {
if(typedArray ==null){return def;}
return typedArray.getBoolean(index, def);
? ? }
/*******************************************************/
/**
* 陰影半徑
*/
? ? private int shadowRadius;
? ? /**
* 陰影Y偏移px
*/
? ? private int shadowOffset;
? ? /**
* 陰影顏色
*/
? ? private int shadowColor ;
? ? /**
* 背景半徑
*/
? ? private float viewRadius;
? ? /**
* 按鈕半徑
*/
? ? private float buttonRadius;
? ? /**
* 背景高
*/
? ? private float height ;
? ? /**
* 背景寬
*/
? ? private float width;
? ? /**
* 背景位置
*/
? ? private float left? ;
? ? private float top? ? ;
? ? private float right? ;
? ? private float bottom ;
? ? private float centerX;
? ? private float centerY;
? ? /**
* 背景底色
*/
? ? private int background;
? ? /**
* 背景關(guān)閉顏色
*/
? ? private int uncheckColor;
? ? /**
* 背景打開顏色
*/
? ? private int checkedColor;
? ? /**
* 邊框?qū)挾萷x
*/
? ? private int borderWidth;
? ? /**
* 打開指示線顏色
*/
? ? private int checkLineColor;
? ? /**
* 打開指示線寬
*/
? ? private int checkLineWidth;
? ? /**
* 打開指示線長
*/
? ? private float checkLineLength;
? ? /**
* 關(guān)閉圓圈顏色
*/
? ? private int uncheckCircleColor;
? ? /**
*關(guān)閉圓圈線寬
*/
? ? private int uncheckCircleWidth;
? ? /**
*關(guān)閉圓圈位移X
*/
? ? private float uncheckCircleOffsetX;
? ? /**
*關(guān)閉圓圈半徑
*/
? ? private float uncheckCircleRadius;
? ? /**
*打開指示線位移X
*/
? ? private float checkedLineOffsetX;
? ? /**
*打開指示線位移Y
*/
? ? private float checkedLineOffsetY;
? ? /**
* 按鈕最左邊
*/
? ? private float buttonMinX;
? ? /**
* 按鈕最右邊
*/
? ? private float buttonMaxX;
? ? /**
* 按鈕畫筆
*/
? ? private PaintbuttonPaint;
? ? /**
* 背景畫筆
*/
? ? private Paintpaint;
? ? /**
* 當(dāng)前狀態(tài)
*/
? ? private ViewStateviewState;
? ? private ViewStatebeforeState;
? ? private ViewStateafterState;
? ? private RectFrect =new RectF();
? ? /**
* 動(dòng)畫狀態(tài)
*/
? ? private int animateState =ANIMATE_STATE_NONE;
? ? /**
*
*/
? ? private ValueAnimatorvalueAnimator;
? ? private final android.animation.ArgbEvaluatorargbEvaluator
? ? ? ? ? ? =new android.animation.ArgbEvaluator();
? ? /**
*是否選中
*/
? ? private boolean isChecked;
? ? /**
* 是否啟用動(dòng)畫
*/
? ? private boolean enableEffect;
? ? /**
* 是否啟用陰影效果
*/
? ? private boolean shadowEffect;
? ? /**
* 是否顯示指示器
*/
? ? private boolean showIndicator;
? ? /**
* 收拾是否按下
*/
? ? private boolean isTouchingDown =false;
? ? /**
*
*/
? ? private boolean isUiInited =false;
? ? /**
*
*/
? ? private boolean isEventBroadcast =false;
? ? private OnCheckedChangeListeneronCheckedChangeListener;
? ? /**
* 手勢按下的時(shí)刻
*/
? ? private long touchDownTime;
? ? private RunnablepostPendingDrag =new Runnable() {
@Override
? ? ? ? public void run() {
if(!isInAnimating()){
pendingDragState();
? ? ? ? ? ? }
}
};
? ? private ValueAnimator.AnimatorUpdateListeneranimatorUpdateListener
? ? ? ? ? ? =new ValueAnimator.AnimatorUpdateListener() {
@Override
? ? ? ? public void onAnimationUpdate(ValueAnimator animation) {
float value = (Float) animation.getAnimatedValue();
? ? ? ? ? ? switch (animateState) {
case ANIMATE_STATE_PENDING_SETTLE: {
}
case ANIMATE_STATE_PENDING_RESET: {
}
case ANIMATE_STATE_PENDING_DRAG: {
viewState.checkedLineColor = (Integer) (argbEvaluator.evaluate(
value,
? ? ? ? ? ? ? ? ? ? ? ? ? ? beforeState.checkedLineColor,
? ? ? ? ? ? ? ? ? ? ? ? ? ? afterState.checkedLineColor
? ? ? ? ? ? ? ? ? ? ));
? ? ? ? ? ? ? ? ? ? viewState.radius =beforeState.radius
? ? ? ? ? ? ? ? ? ? ? ? ? ? + (afterState.radius -beforeState.radius) * value;
? ? ? ? ? ? ? ? ? ? if(animateState !=ANIMATE_STATE_PENDING_DRAG){
viewState.buttonX =beforeState.buttonX
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? + (afterState.buttonX -beforeState.buttonX) * value;
? ? ? ? ? ? ? ? ? ? }
viewState.checkStateColor = (Integer)argbEvaluator.evaluate(
value,
? ? ? ? ? ? ? ? ? ? ? ? ? ? beforeState.checkStateColor,
? ? ? ? ? ? ? ? ? ? ? ? ? ? afterState.checkStateColor
? ? ? ? ? ? ? ? ? ? );
break;
? ? ? ? ? ? ? ? }
case ANIMATE_STATE_SWITCH: {
viewState.buttonX =beforeState.buttonX
? ? ? ? ? ? ? ? ? ? ? ? ? ? + (afterState.buttonX -beforeState.buttonX) * value;
? ? ? ? ? ? ? ? ? ? float fraction = (viewState.buttonX -buttonMinX) / (buttonMaxX -buttonMinX);
? ? ? ? ? ? ? ? ? ? viewState.checkStateColor = (Integer)argbEvaluator.evaluate(
fraction,
? ? ? ? ? ? ? ? ? ? ? ? ? ? uncheckColor,
? ? ? ? ? ? ? ? ? ? ? ? ? ? checkedColor
? ? ? ? ? ? ? ? ? ? );
? ? ? ? ? ? ? ? ? ? viewState.radius = fraction *viewRadius;
? ? ? ? ? ? ? ? ? ? viewState.checkedLineColor = (Integer)argbEvaluator.evaluate(
fraction,
? ? ? ? ? ? ? ? ? ? ? ? ? ? Color.TRANSPARENT,
? ? ? ? ? ? ? ? ? ? ? ? ? ? checkLineColor
? ? ? ? ? ? ? ? ? ? );
break;
? ? ? ? ? ? ? ? }
default:
case ANIMATE_STATE_DRAGING: {
}
case ANIMATE_STATE_NONE: {
break;
? ? ? ? ? ? ? ? }
}
postInvalidate();
? ? ? ? }
};
? ? private Animator.AnimatorListeneranimatorListener
? ? ? ? ? ? =new Animator.AnimatorListener() {
@Override
? ? ? ? public void onAnimationStart(Animator animation) {
}
@Override
? ? ? ? public void onAnimationEnd(Animator animation) {
switch (animateState) {
case ANIMATE_STATE_DRAGING: {
break;
? ? ? ? ? ? ? ? }
case ANIMATE_STATE_PENDING_DRAG: {
animateState =ANIMATE_STATE_DRAGING;
? ? ? ? ? ? ? ? ? ? viewState.checkedLineColor = Color.TRANSPARENT;
? ? ? ? ? ? ? ? ? ? viewState.radius =viewRadius;
? ? ? ? ? ? ? ? ? ? postInvalidate();
break;
? ? ? ? ? ? ? ? }
case ANIMATE_STATE_PENDING_RESET: {
animateState =ANIMATE_STATE_NONE;
? ? ? ? ? ? ? ? ? ? postInvalidate();
break;
? ? ? ? ? ? ? ? }
case ANIMATE_STATE_PENDING_SETTLE: {
animateState =ANIMATE_STATE_NONE;
? ? ? ? ? ? ? ? ? ? postInvalidate();
? ? ? ? ? ? ? ? ? ? broadcastEvent();
break;
? ? ? ? ? ? ? ? }
case ANIMATE_STATE_SWITCH: {
isChecked = !isChecked;
? ? ? ? ? ? ? ? ? ? animateState =ANIMATE_STATE_NONE;
? ? ? ? ? ? ? ? ? ? postInvalidate();
? ? ? ? ? ? ? ? ? ? broadcastEvent();
break;
? ? ? ? ? ? ? ? }
default:
case ANIMATE_STATE_NONE: {
break;
? ? ? ? ? ? ? ? }
}
}
@Override
? ? ? ? public void onAnimationCancel(Animator animation) {
}
@Override
? ? ? ? public void onAnimationRepeat(Animator animation) {
}
};
? ? /*******************************************************/
/**
* 保存動(dòng)畫狀態(tài)
* */
? ? private static class ViewState {
/**
* 按鈕x位置[buttonMinX-buttonMaxX]
*/
? ? ? ? float buttonX;
? ? ? ? /**
* 狀態(tài)背景顏色
*/
? ? ? ? int checkStateColor;
? ? ? ? /**
* 選中線的顏色
*/
? ? ? ? int checkedLineColor;
? ? ? ? /**
* 狀態(tài)背景的半徑
*/
? ? ? ? float radius;
? ? ? ? ViewState(){}
private void copy(ViewState source){
this.buttonX = source.buttonX;
? ? ? ? ? ? this.checkStateColor = source.checkStateColor;
? ? ? ? ? ? this.checkedLineColor = source.checkedLineColor;
? ? ? ? ? ? this.radius = source.radius;
? ? ? ? }
}
}
2别垮,新建switch_button_attrs.xml
<declare-styleable name="SwitchButton">
? ? <attr name="sb_shadow_radius" format="reference|dimension" />
? ? <attr name="sb_shadow_offset" format="reference|dimension" />
? ? <attr name="sb_shadow_color" format="reference|color" />
? ? <attr name="sb_uncheck_color" format="reference|color" />
? ? <attr name="sb_checked_color" format="reference|color" />
? ? <attr name="sb_border_width" format="reference|dimension" />
? ? <attr name="sb_checkline_color" format="reference|color" />
? ? <attr name="sb_checkline_width" format="reference|dimension" />
? ? <attr name="sb_uncheckcircle_color" format="reference|color" />
? ? <attr name="sb_uncheckcircle_width" format="reference|dimension" />
? ? <attr name="sb_uncheckcircle_radius" format="reference|dimension" />
? ? <attr name="sb_checked" format="reference|boolean" />
? ? <attr name="sb_shadow_effect" format="reference|boolean" />
? ? <attr name="sb_effect_duration" format="reference|integer" />
? ? <attr name="sb_button_color" format="reference|color" />
? ? <attr name="sb_show_indicator" format="reference|boolean" />
? ? <attr name="sb_background" format="reference|color" />
? ? <attr name="sb_enable_effect" format="reference|boolean" />
</declare-styleable>
3.xml中使用
<*****SwitchButton
? ? android:id="@+id/sb_xxtz"
? ? android:layout_width="50dp"
? ? android:layout_height="30dp"
? ? app:sb_checked="true"
? ? app:sb_show_indicator="false"
? ? app:sb_uncheck_color="#fff"http://未選中顏色
? ? app:sb_checked_color="#FFF8B702"http://選中顏色
? ? android:layout_alignParentTop="true"
? ? android:layout_alignParentEnd="true"/>
這樣就OK了!