基于SlipButton教你如何实现ios7的选择器效果

这是ios7的效果,因为新来的测试机我还不清楚还不知道 怎么用截图功能 就先从别人那里借了一个效果图过来!

package com.zf.view;

import com.zf.R;

import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.view.ViewParent;
import android.widget.CheckBox;

public class UISwitchButton 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 = true;
 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 = 82;// 默认宽度
 private final int COMMON_HEIGHT_IN_PIXEL = 50;// 默认高度

 public UISwitchButton(Context context, AttributeSet attrs) {
  this(context, attrs, android.R.attr.checkboxStyle);
 }

 public UISwitchButton(Context context) {
  this(context, null);
 }

 public UISwitchButton(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.drawable.switch_btn_bg_green);
  bmBgWhite = BitmapFactory.decodeResource(resources,
    R.drawable.switch_btn_bg_white);
  bmBtnNormal = BitmapFactory.decodeResource(resources,
    R.drawable.switch_btn_normal);
  bmBtnPressed = BitmapFactory.decodeResource(resources,
    R.drawable.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 = 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;
   invalidate();

   if (mBroadcasting) {
    // NO-OP
    return;
   }
   // 正在执行监听事件
   mBroadcasting = true;
   if (mOnCheckedChangeListener != null) {
    mOnCheckedChangeListener.onCheckedChanged(UISwitchButton.this,
      mChecked);
   }
   if (mOnCheckedChangeWidgetListener != null) {
    mOnCheckedChangeWidgetListener.onCheckedChanged(
      UISwitchButton.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;
   }
  }
 };
}
package com.zf;

import com.zf.view.UISwitchButton;

import android.app.Activity;
import android.os.Bundle;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.Toast;

public class TestActivity extends Activity {
 private UISwitchButton switch1;
 private UISwitchButton switch2;
 

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_test);
  initView();
 }

 private void initView() {
  switch1 = (UISwitchButton) findViewById(R.id.switch1);
  
  switch1.setOnCheckedChangeListener(new OnCheckedChangeListener() {
   @Override
   public void onCheckedChanged(CompoundButton buttonView,
     boolean isChecked) {
    if (isChecked) {
     Toast.makeText(TestActivity.this, "开启", Toast.LENGTH_SHORT)
       .show();
    } else {
     Toast.makeText(TestActivity.this, "关闭", Toast.LENGTH_SHORT)
       .show();
    }
   }
  });
 }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <com.zf.view.UISwitchButton
        xmlns:switch="http://schemas.android.com/apk/res-auto"
        android:id="@+id/switch1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        switch:bmHeight="50dp"
        switch:bmWidth="70dp" />


</LinearLayout>
  项目下载地址:http://download.csdn.net/detail/ningzhouxu/9530108

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值