自定義SwitchButton切換樣式磁玉,一行代碼搞定(轉(zhuǎn))

使用步驟:

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了!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末扎谎,一起剝皮案震驚了整個(gè)濱河市碳想,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌毁靶,老刑警劉巖胧奔,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異预吆,居然都是意外死亡龙填,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門拐叉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來岩遗,“玉大人,你說我怎么就攤上這事凤瘦∷藿福” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵蔬芥,是天一觀的道長梆靖。 經(jīng)常有香客問我,道長笔诵,這世上最難降的妖魔是什么返吻? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮乎婿,結(jié)果婚禮上测僵,老公的妹妹穿的比我還像新娘。我一直安慰自己谢翎,他們只是感情好捍靠,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著岳服,像睡著了一般剂公。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上吊宋,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天纲辽,我揣著相機(jī)與錄音,去河邊找鬼璃搜。 笑死拖吼,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的这吻。 我是一名探鬼主播吊档,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼唾糯!你這毒婦竟也來了怠硼?” 一聲冷哼從身側(cè)響起鬼贱,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎香璃,沒想到半個(gè)月后这难,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡葡秒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年姻乓,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片眯牧。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蹋岩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出学少,到底是詐尸還是另有隱情剪个,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布旱易,位于F島的核電站禁偎,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏阀坏。R本人自食惡果不足惜如暖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望忌堂。 院中可真熱鬧盒至,春花似錦、人聲如沸士修。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽棋嘲。三九已至酒唉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間沸移,已是汗流浹背痪伦。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留雹锣,地道東北人网沾。 一個(gè)月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像蕊爵,于是被迫代替她去往敵國和親辉哥。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容