/** * 滑动开关效果 * */ @SuppressLint("Recycle") public class SwitchButton extends View { private final String TAG = "SwitchButton"; private Bitmap mCriNor; private Bitmap mCriPre; private Bitmap mBackBlack; private Bitmap mBackWhite; private Bitmap mBackLong; private Bitmap mBackSlide; private float deltX = 0; private boolean isTouch = false; private Rect dst; private int thumbRadius;//thumb的半径 private int lastLength;//criNor超出空间的长度 private PorterDuffXfermode mode; private Paint mPaint; private ValueAnimator mAnimator; private boolean cacheIsOpen = false; private boolean isOpen = false; public SwitchButton(Context context, AttributeSet attrs) { super(context, attrs); /*TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SwitchButton); typedArray.recycle();*/ init(); } private void init() { mCriNor = BitmapFactory.decodeResource(getResources(), R.drawable.cri_nor); mCriPre = BitmapFactory.decodeResource(getResources(), R.drawable.cri_pre); mBackBlack = BitmapFactory.decodeResource(getResources(), R.drawable.back_black); mBackWhite = BitmapFactory.decodeResource(getResources(), R.drawable.back_white); mBackLong = BitmapFactory.decodeResource(getResources(), R.drawable.back_long); dst = new Rect(0, 0, mBackWhite.getWidth(), mBackWhite.getHeight()); lastLength = mCriNor.getWidth() - mBackBlack.getWidth(); thumbRadius = (mCriNor.getWidth() - lastLength*2)/2; mode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN); mPaint = new Paint(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(mBackWhite.getWidth(), mBackWhite.getHeight()); } @Override protected void onDraw(Canvas canvas) { //绘制背景 canvas.drawBitmap(mBackWhite, new Matrix(), null); //绘制滑动背景图 drawSlideBack(canvas); //绘制滑动按钮 drawCriBtn(canvas); } private void drawSlideBack(Canvas canvas) { if(deltX <= thumbRadius){ deltX = thumbRadius; } if(deltX >= getMeasuredWidth() - thumbRadius){ deltX = getMeasuredWidth() - thumbRadius; } mBackSlide = getSlideBackBitmap(); canvas.drawBitmap(mBackSlide, 0, 0, null); } private void drawCriBtn(Canvas canvas) { if(deltX <= thumbRadius){ deltX = thumbRadius; } if(deltX >= getMeasuredWidth() - thumbRadius){ deltX = getMeasuredWidth() - thumbRadius; } Bitmap bitmap = isTouch ? mCriPre : mCriNor; int clipX = (int) (lastLength - (deltX - thumbRadius)); Rect src = new Rect(clipX, 0, getMeasuredWidth() + clipX, bitmap.getHeight()); canvas.drawBitmap(bitmap, src, dst, null); Log.e(TAG, "draw cri btn: deltX = " + deltX); } private Bitmap getSlideBackBitmap(){ mPaint.setXfermode(mode); Bitmap bitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Config.ARGB_8888); Canvas c = new Canvas(bitmap); int clipX = (int) (lastLength - (deltX - thumbRadius)); Rect src = new Rect(clipX, 0, getMeasuredWidth() + clipX, mBackLong.getHeight()); c.drawBitmap(mBackLong, src, dst, null); c.drawBitmap(mBackBlack, 0, 0, mPaint); mPaint.setXfermode(null); return bitmap; } @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: deltX = event.getX(); isTouch = true; if(mAnimator != null && mAnimator.isRunning()){ return false; } break; case MotionEvent.ACTION_MOVE: deltX = event.getX(); isTouch = true; break; case MotionEvent.ACTION_UP: deltX = event.getX(); isTouch = false; switchState(); break; default: break; } Log.e(TAG, "deltX = " + deltX); invalidate(); return true; } private void switchState() { if(deltX >0 && deltX <= getMeasuredWidth()/2){//去左边 isOpen = false; anim(deltX, 0); }else if(deltX > getMeasuredWidth()/2 && deltX < getMeasuredWidth()){//去右边 isOpen = true; anim(deltX, getMeasuredWidth()); }else if(deltX <= 0){ isOpen = false; handleChange(); }else if(deltX >= getMeasuredHeight()){ isOpen = true; handleChange(); } } private void anim(float beginX,float endX){ mAnimator = ValueAnimator.ofFloat(beginX,endX); mAnimator.setDuration((long)(Math.abs(beginX - endX)*5)); mAnimator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { deltX = (Float) animation.getAnimatedValue(); invalidate(); } }); mAnimator.addListener(new AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { handleChange(); } @Override public void onAnimationCancel(Animator animation) { } }); mAnimator.start(); } private void handleChange(){ if(listener != null && isOpen != cacheIsOpen){ cacheIsOpen = isOpen; listener.onChange(SwitchButton.this, cacheIsOpen); } } OnSwitchChangeListener listener; public void setOnSwitChangeListener(OnSwitchChangeListener listener){ this.listener = listener; } public interface OnSwitchChangeListener{ void onChange(SwitchButton switchBtn,boolean isOpen); } }