package com.material.widget; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.support.annotation.NonNull; import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.CompoundButton; /** * Created by keith on 14-9-29. * User keith * Date 14-9-29 * Time 下午10:08 */ public class Switch extends CompoundButton { private static final String TAG = Switch.class.getSimpleName(); private static final long ANIMATION_DURATION = 200; private static final int StateNormal = 1; private static final int StateTouchDown = 2; private static final int StateTouchUp = 3; private int mState = StateNormal; private long mStartTime; private int mSwitchWidth; private int mSwitchHeight; private int mTrackColor; private int mTrackCheckedColor; private int mThumbColor; private int mThumbCheckedColor; private int mSwitchThumbRadius; private int mSwitchRippleMaxRadius; private int mStrokeWidth; private int mTrackWidth; private Paint trackPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private Paint ripplePaint = new Paint(Paint.ANTI_ALIAS_FLAG); private Paint thumbFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private Paint thumbStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); public Switch(Context context) { this(context, null); } public Switch(Context context, AttributeSet attrs) { this(context, attrs, 0); } public Switch(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mSwitchWidth = getResources().getDimensionPixelSize(R.dimen.switch_width); mSwitchHeight = getResources().getDimensionPixelSize(R.dimen.switch_height); mTrackColor = getResources().getColor(R.color.switch_track_color); mTrackCheckedColor = getResources().getColor(R.color.switch_track_checked_color); mThumbColor = getResources().getColor(R.color.switch_thumb_color); mThumbCheckedColor = getResources().getColor(R.color.switch_thumb_checked_color); mSwitchThumbRadius = getResources().getDimensionPixelSize(R.dimen.switch_thumb_radius); mSwitchRippleMaxRadius = getResources().getDimensionPixelSize(R.dimen.switch_ripple_max_radius); mStrokeWidth = getResources().getDimensionPixelSize(R.dimen.switch_stroke_width); mTrackWidth = getResources().getDimensionPixelSize(R.dimen.switch_track_width); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { widthMeasureSpec = MeasureSpec.makeMeasureSpec(measureWidth(widthMeasureSpec), MeasureSpec.EXACTLY); heightMeasureSpec = MeasureSpec.makeMeasureSpec(measureHeight(heightMeasureSpec), MeasureSpec.EXACTLY); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } private int measureWidth(int measureSpec) { int result; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { if (specSize < mSwitchWidth) { result = mSwitchWidth; } else { result = specSize; } } else { result = mSwitchWidth; } return result; } private int measureHeight(int measureSpec) { int result; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { if (specSize < mSwitchHeight) { result = mSwitchHeight; } else { result = specSize; } } else { result = mSwitchHeight; } return result; } private boolean contains(MotionEvent event) { if (isChecked()) { return event.getX() >= getWidth() - (getWidth() - mSwitchWidth) / 2 - mSwitchRippleMaxRadius * 2 && event.getX() <= getWidth() - (getWidth() - mSwitchWidth) / 2 && event.getY() >= (getHeight() - mSwitchHeight) / 2 && event.getY() <= (getHeight() - mSwitchHeight) / 2 + mSwitchRippleMaxRadius * 2; } else { return event.getX() >= (getWidth() - mSwitchWidth) / 2 && event.getX() <= (getWidth() - mSwitchWidth) / 2 + mSwitchRippleMaxRadius * 2 && event.getY() >= (getHeight() - mSwitchHeight) / 2 && event.getY() <= (getHeight() - mSwitchHeight) / 2 + mSwitchRippleMaxRadius * 2; } } private int rippleColor(int color) { int alpha = Math.round(Color.alpha(color) * 0.3f); int red = Color.red(color); int green = Color.green(color); int blue = Color.blue(color); return Color.argb(alpha, red, green, blue); } @Override public boolean onTouchEvent(@NonNull MotionEvent event) { if (isChecked()) { if (contains(event)) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mState = StateTouchDown; invalidate(); break; case MotionEvent.ACTION_MOVE: break; case MotionEvent.ACTION_UP: mState = StateNormal; setChecked(false); invalidate(); break; } } else { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: break; case MotionEvent.ACTION_UP: break; } } } else { if (contains(event)) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mState = StateTouchDown; mStartTime = System.currentTimeMillis(); invalidate(); break; case MotionEvent.ACTION_MOVE: break; case MotionEvent.ACTION_UP: mState = StateNormal; setChecked(true); invalidate(); break; } } else { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: break; case MotionEvent.ACTION_UP: break; } } } return true; } @Override protected void onDraw(@NonNull Canvas canvas) { super.onDraw(canvas); if (isChecked()) { trackPaint.setStrokeWidth(mTrackWidth); trackPaint.setColor(mTrackCheckedColor); canvas.drawLine((getWidth() - mSwitchWidth) / 2 + mSwitchRippleMaxRadius + mSwitchThumbRadius, getHeight() / 2, getWidth() - mSwitchRippleMaxRadius - mSwitchThumbRadius, getHeight() / 2, trackPaint); switch (mState) { case StateTouchDown: ripplePaint.setColor(rippleColor(mThumbCheckedColor)); canvas.drawCircle(getWidth() - (getWidth() - mSwitchWidth) / 2 - mSwitchRippleMaxRadius, getHeight() / 2, mSwitchRippleMaxRadius, ripplePaint); break; case StateTouchUp: break; case StateNormal: break; } thumbFillPaint.setColor(mThumbCheckedColor); thumbFillPaint.setStyle(Paint.Style.FILL); canvas.drawCircle(getWidth() - (getWidth() - mSwitchWidth) / 2 - mSwitchRippleMaxRadius, getHeight() / 2, mSwitchThumbRadius, thumbFillPaint); } else { trackPaint.setStrokeWidth(mTrackWidth); trackPaint.setColor(mTrackColor); canvas.drawLine((getWidth() - mSwitchWidth) / 2 + mSwitchRippleMaxRadius + mSwitchThumbRadius, getHeight() / 2, getWidth() - mSwitchRippleMaxRadius - mSwitchThumbRadius, getHeight() / 2, trackPaint); switch (mState) { case StateTouchDown: ripplePaint.setColor(rippleColor(mThumbColor)); canvas.drawCircle((getWidth() - mSwitchWidth) / 2 + mSwitchRippleMaxRadius, getHeight() / 2, mSwitchRippleMaxRadius, ripplePaint); break; case StateTouchUp: break; case StateNormal: break; } thumbStrokePaint.setColor(mThumbColor); thumbStrokePaint.setStyle(Paint.Style.STROKE); thumbStrokePaint.setStrokeWidth(mStrokeWidth); canvas.drawCircle((getWidth() - mSwitchWidth) / 2 + mSwitchRippleMaxRadius, getHeight() / 2, mSwitchThumbRadius, thumbStrokePaint); } } }