SwitchButton自定义开关

来源:互联网 发布:linux socket编程实例 编辑:程序博客网 时间:2024/05/18 12:36
public class SwitchButton extends CheckBox {   private Paint mPaint;   private RectF mSaveLayerRectF;   private float mFirstDownY;   private float mFirstDownX;   private int mClickTimeout;   private int mTouchSlop;   private final int MAX_ALPHA = 255;   private int mAlpha = MAX_ALPHA;   private boolean mChecked = false;   private boolean mBroadcasting;// 标示是否正在执行监听事件中   private boolean mTurningOn;// 标示位置是否达到开启状态   private PerformClick mPerformClick;   private OnCheckedChangeListener mOnCheckedChangeListener;   private OnCheckedChangeListener mOnCheckedChangeWidgetListener;   private boolean mAnimating;// 标示是否继续执行移动动画   private final float VELOCITY = 350;// 定义按钮动画移动的最大长度   private float mVelocity;// 按钮动画移动的最大像素长度   private float mAnimationPosition;// 按钮动画移动的当前位置   private float mAnimatedVelocity;// 按钮动画移动的实际位移(+mVelocity/-mVelocity)   private Bitmap bmBgGreen;// 绿色背景   private Bitmap bmBgWhite;// 白色背景   private Bitmap bmBtnNormal;// 未按下时按钮   private Bitmap bmBtnPressed;// 按下时按钮   private Bitmap bmCurBtnPic;// 当前显示的按钮图片   private Bitmap bmCurBgPic;// 当前背景图片   private float bgWidth;// 背景宽度   private float bgHeight;// 背景宽度   private float btnWidth;// 按钮宽度   private float offBtnPos;// 按钮关闭时位置   private float onBtnPos;// 按钮开启时位置   private float curBtnPos;// 按钮当前位置   private float startBtnPos;// 开始按钮位置   private final int COMMON_WIDTH_IN_PIXEL = 225;// 默认宽度   private final int COMMON_HEIGHT_IN_PIXEL = 115;// 默认高度   public SwitchButton(Context context, AttributeSet attrs) {      this(context, attrs, android.R.attr.checkboxStyle);   }   public SwitchButton(Context context) {      this(context, null);   }   public SwitchButton(Context context, AttributeSet attrs, int defStyle) {      super(context, attrs, defStyle);      init(context, attrs);   }   private void init(Context context, AttributeSet attrs) {      mPaint = new Paint();      mPaint.setColor(Color.WHITE);      Resources resources = context.getResources();      // get attrConfiguration      TypedArray array = context.obtainStyledAttributes(attrs,            R.styleable.SwitchButton);      int width = (int) array.getDimensionPixelSize(            R.styleable.SwitchButton_bmWidth, 0);      int height = (int) array.getDimensionPixelSize(            R.styleable.SwitchButton_bmHeight, 0);      array.recycle();      // size width or height      if (width <= 0 || height <= 0) {         width = COMMON_WIDTH_IN_PIXEL;         height = COMMON_HEIGHT_IN_PIXEL;      } else {         float scale = (float) COMMON_WIDTH_IN_PIXEL               / COMMON_HEIGHT_IN_PIXEL;         if ((float) width / height > scale) {            width = (int) (height * scale);         } else if ((float) width / height < scale) {            height = (int) (width / scale);         }      }      // get viewConfiguration      mClickTimeout = ViewConfiguration.getPressedStateDuration()            + ViewConfiguration.getTapTimeout();      mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();      // get Bitmap      bmBgGreen = BitmapFactory.decodeResource(resources,            R.mipmap.switch_btn_bg_on);      bmBgWhite = BitmapFactory.decodeResource(resources,            R.mipmap.switch_btn_bg_off);      bmBtnNormal = BitmapFactory.decodeResource(resources,            R.mipmap.switch_btn_normal);      bmBtnPressed = BitmapFactory.decodeResource(resources,            R.mipmap.switch_btn_pressed);      // size Bitmap      bmBgGreen = Bitmap.createScaledBitmap(bmBgGreen, width, height, true);      bmBgWhite = Bitmap.createScaledBitmap(bmBgWhite, width, height, true);      bmBtnNormal = Bitmap.createScaledBitmap(bmBtnNormal, height, height,            true);      bmBtnPressed = Bitmap.createScaledBitmap(bmBtnPressed, height, height,            true);      bmCurBtnPic = bmBtnPressed;// 初始按钮图片//    bmCurBtnPic = mChecked ? bmBtnPressed : bmBtnNormal;// 初始按钮图片      bmCurBgPic = mChecked ? bmBgGreen : bmBgWhite;// 初始背景图片      bgWidth = bmBgGreen.getWidth();// 背景宽度      bgHeight = bmBgGreen.getHeight();// 背景高度      btnWidth = bmBtnNormal.getWidth();// 按钮宽度      offBtnPos = 0;// 关闭时在最左边      onBtnPos = bgWidth - btnWidth;// 开始时在右边      curBtnPos = mChecked ? onBtnPos : offBtnPos;// 按钮当前为初始位置      // get density      float density = resources.getDisplayMetrics().density;      mVelocity = (int) (VELOCITY * density + 0.5f);// 动画距离      mSaveLayerRectF = new RectF(0, 0, bgWidth, bgHeight);   }   @Override   public void setEnabled(boolean enabled) {      mAlpha = enabled ? MAX_ALPHA : MAX_ALPHA / 3;      super.setEnabled(enabled);   }   public boolean isChecked() {      return mChecked;   }   public void toggle() {      setChecked(!mChecked);   }   private void setCheckedDelayed(final boolean checked) {      postDelayed(new Runnable() {         @Override         public void run() {            setChecked(checked);         }      }, 10);   }   public void setChecked(boolean checked) {      if (mChecked != checked) {         mChecked = checked;         // 初始化按钮位置         curBtnPos = checked ? onBtnPos : offBtnPos;         // 改变背景图片         bmCurBgPic = checked ? bmBgGreen : bmBgWhite;         bmCurBtnPic = checked ? bmBtnNormal : bmBtnPressed;         invalidate();         if (mBroadcasting) {            // NO-OP            return;         }         // 正在执行监听事件         mBroadcasting = true;         if (mOnCheckedChangeListener != null) {            mOnCheckedChangeListener.onCheckedChanged(SwitchButton.this,                  mChecked);         }         if (mOnCheckedChangeWidgetListener != null) {            mOnCheckedChangeWidgetListener.onCheckedChanged(                  SwitchButton.this, mChecked);         }         // 监听事件结束         mBroadcasting = false;      }   }   public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {      mOnCheckedChangeListener = listener;   }   void setOnCheckedChangeWidgetListener(OnCheckedChangeListener listener) {      mOnCheckedChangeWidgetListener = listener;   }   @Override   public boolean onTouchEvent(MotionEvent event) {      int action = event.getAction();      float x = event.getX();      float y = event.getY();      float deltaX = Math.abs(x - mFirstDownX);      float deltaY = Math.abs(y - mFirstDownY);      switch (action) {      case MotionEvent.ACTION_DOWN:         ViewParent mParent = getParent();         if (mParent != null) {            // 通知父控件不要拦截本view的触摸事件            mParent.requestDisallowInterceptTouchEvent(true);         }         mFirstDownX = x;         mFirstDownY = y;         bmCurBtnPic = bmBtnPressed;         startBtnPos = mChecked ? onBtnPos : offBtnPos;         break;      case MotionEvent.ACTION_MOVE:         float time = event.getEventTime() - event.getDownTime();         curBtnPos = startBtnPos + event.getX() - mFirstDownX;         if (curBtnPos >= onBtnPos) {            curBtnPos = onBtnPos;         }         if (curBtnPos <= offBtnPos) {            curBtnPos = offBtnPos;         }         mTurningOn = curBtnPos > bgWidth / 2 - btnWidth / 2;         break;      case MotionEvent.ACTION_UP:         bmCurBtnPic = bmBtnNormal;         time = event.getEventTime() - event.getDownTime();         if (deltaY < mTouchSlop && deltaX < mTouchSlop               && time < mClickTimeout) {            if (mPerformClick == null) {               mPerformClick = new PerformClick();            }            if (!post(mPerformClick)) {               performClick();            }         } else {            startAnimation(mTurningOn);         }         break;      }      invalidate();      return isEnabled();   }   private class PerformClick implements Runnable {      public void run() {         performClick();      }   }   @Override   public boolean performClick() {      startAnimation(!mChecked);      return true;   }   @Override   protected void onDraw(Canvas canvas) {      canvas.saveLayerAlpha(mSaveLayerRectF, mAlpha, Canvas.MATRIX_SAVE_FLAG            | Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG            | Canvas.FULL_COLOR_LAYER_SAVE_FLAG            | Canvas.CLIP_TO_LAYER_SAVE_FLAG);      // 绘制底部图片      canvas.drawBitmap(bmCurBgPic, 0, 0, mPaint);      // 绘制按钮      canvas.drawBitmap(bmCurBtnPic, curBtnPos, 0, mPaint);      canvas.restore();   }   @Override   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {      setMeasuredDimension((int) bgWidth, (int) bgHeight);   }   private void startAnimation(boolean turnOn) {      mAnimating = true;      mAnimatedVelocity = turnOn ? mVelocity : -mVelocity;      mAnimationPosition = curBtnPos;      new SwitchAnimation().run();   }   private void stopAnimation() {      mAnimating = false;   }   private final class SwitchAnimation implements Runnable {      @Override      public void run() {         if (!mAnimating) {            return;         }         doAnimation();         requestAnimationFrame(this);      }   }   private void doAnimation() {      mAnimationPosition += mAnimatedVelocity * ANIMATION_FRAME_DURATION            / 1000;      if (mAnimationPosition <= offBtnPos) {         stopAnimation();         mAnimationPosition = offBtnPos;         setCheckedDelayed(false);      } else if (mAnimationPosition >= onBtnPos) {         stopAnimation();         mAnimationPosition = onBtnPos;         setCheckedDelayed(true);      }      curBtnPos = mAnimationPosition;      invalidate();   }   private static final int MSG_ANIMATE = 1000;   public static final int ANIMATION_FRAME_DURATION = 1000 / 60;   public void requestAnimationFrame(Runnable runnable) {      Message message = new Message();      message.what = MSG_ANIMATE;      message.obj = runnable;      mHandler.sendMessageDelayed(message, ANIMATION_FRAME_DURATION);   }   private Handler mHandler = new Handler() {      public void handleMessage(Message m) {         switch (m.what) {         case MSG_ANIMATE:            if (m.obj != null) {               ((Runnable) m.obj).run();            }            break;         }      }   };}style:
<declare-styleable name="SwitchButton">    <attr name="bmWidth" format="dimension"/>    <attr name="bmHeight" format="dimension"/></declare-styleable>

图片文件就不上传了
 





0 0