2013-12-28 17:25:01

网上看到一篇关于可滑动的ToogleButton的文章,有代码,觉得挺好,但是不符合我的要求,因此在他的代码基础上改了一些。(作者看到了勿喷啊,实在找不到原文了,只好把代码下载地址贴出来。)

源码下载地址: http://download.csdn.net/detail/zshq280017423/4240703

先来两张效果图:

然后上代码:

最主要的类是SlipButton.java

  1 package com.util;
  2 
  3 import android.content.Context;
  4 import android.graphics.Bitmap;
  5 import android.graphics.BitmapFactory;
  6 import android.graphics.Canvas;
  7 import android.graphics.Matrix;
  8 import android.graphics.Paint;
  9 import android.util.AttributeSet;
 10 import android.util.Log;
 11 import android.view.MotionEvent;
 12 import android.view.View;
 13 import android.view.View.OnTouchListener;
 14 
 15 import com.view.SlipButton.R;
 16 
 17 public class SlipButton extends View implements OnTouchListener {
 18 
 19     private float DownX, NowX;// 按下时的x,当前的x
 20     private float btn_on_left = 0;
 21     private float btn_off_left = 0;
 22 
 23     private boolean NowChoose = false;// 记录当前按钮是否打开,true为打开,flase为关闭
 24     private boolean isChecked;
 25     private boolean OnSlip = false;// 记录用户是否在滑动的变量
 26     private boolean isChgLsnOn = false;
 27 
 28     private OnChangedListener ChgLsn;
 29     private Bitmap bg_on;
 30     private Bitmap bg_off;
 31     private Bitmap slip_btn;
 32 
 33     public SlipButton(Context context) {
 34         super(context);
 35         init();
 36     }
 37 
 38     public SlipButton(Context context, AttributeSet attrs) {
 39         super(context, attrs);
 40         init();
 41     }
 42 
 43     private void init() { // 初始化
 44         bg_on = BitmapFactory.decodeResource(getResources(),
 45                 R.drawable.split_left_1);
 46         bg_off = BitmapFactory.decodeResource(getResources(),
 47                 R.drawable.split_right_1);
 48         slip_btn = BitmapFactory.decodeResource(getResources(),
 49                 R.drawable.split_1);
 50 
 51         btn_off_left = bg_off.getWidth() - slip_btn.getWidth();
 52 
 53         setOnTouchListener(this); // 设置监听器,也可以直接复写OnTouchEvent
 54     }
 55 
 56     @Override
 57     protected void onDraw(Canvas canvas) {// 绘图函数
 58         super.onDraw(canvas);
 59 
 60         Matrix matrix = new Matrix();
 61         Paint paint = new Paint();
 62         float x;
 63 
 64         if (NowX < (bg_on.getWidth() / 2)) { // 滑动到前半段与后半段的背景不同,在此做判断
 65             x = NowX - slip_btn.getWidth() / 2;
 66             canvas.drawBitmap(bg_off, matrix, paint);// 画出关闭时的背景
 67         } else {
 68             x = bg_on.getWidth() - slip_btn.getWidth() / 2;
 69             canvas.drawBitmap(bg_on, matrix, paint);// 画出打开时的背景
 70         }
 71 
 72         if (OnSlip) {// 是否是在滑动状态,
 73             if (NowX >= bg_on.getWidth()) {// 是否划出指定范围,不能让游标跑到外头,必须做这个判断
 74                 x = bg_on.getWidth() - slip_btn.getWidth() / 2;// 减去游标1/2的长度...
 75             } else if (NowX < 0) {
 76                 x = 0;
 77             } else {
 78                 x = NowX - slip_btn.getWidth() / 2;
 79             }
 80         } else {// 非滑动状态
 81             if (NowChoose) {// 根据现在的开关状态设置画游标的位置
 82                 x = btn_off_left;
 83                 canvas.drawBitmap(bg_on, matrix, paint);// 初始状态为true时应该画出打开状态图片
 84             } else {
 85                 x = btn_on_left;
 86             }
 87         }
 88         if (isChecked) {
 89             canvas.drawBitmap(bg_on, matrix, paint);
 90             x = btn_off_left;
 91             isChecked = !isChecked;
 92         }
 93 
 94         if (x < 0) {// 对游标位置进行异常判断...
 95             x = 0;
 96         } else if (x > bg_on.getWidth() - slip_btn.getWidth()) {
 97             x = bg_on.getWidth() - slip_btn.getWidth();
 98         }
 99         canvas.drawBitmap(slip_btn, x, 0, paint);// 画出游标.
100 
101     }
102 
103     public boolean onTouch(View v, MotionEvent event) {
104         switch (event.getAction()) {// 根据动作来执行代码
105             case MotionEvent.ACTION_DOWN:// 按下
106                 if (event.getX() > bg_on.getWidth()
107                         || event.getY() > bg_on.getHeight()) {
108                     return false;
109                 }
110                 OnSlip = true;
111                 DownX = event.getX();
112                 NowX = DownX;
113                 break;
114 
115             case MotionEvent.ACTION_MOVE:// 滑动
116                 Log.d("David", "event.getX = " + event.getX());
117                 Log.d("David", "event.getY = " + event.getY());
118                 NowX = event.getX();
119                 boolean LastChoose = NowChoose;
120 
121                 if (NowX >= (bg_on.getWidth() / 2)) {
122                     NowChoose = true;
123                 } else {
124                     NowChoose = false;
125                 }
126 
127                 if (isChgLsnOn && (LastChoose != NowChoose)) { // 如果设置了监听器,就调用其方法..
128                     ChgLsn.OnChanged(NowChoose);
129                 }
130                 break;
131 
132             case MotionEvent.ACTION_UP:// 松开
133                 OnSlip = false;
134                 break;
135             default:
136         }
137         invalidate();// 重画控件
138         return true;
139     }
140 
141     public void SetOnChangedListener(OnChangedListener l) {// 设置监听器,当状态修改的时候
142         isChgLsnOn = true;
143         ChgLsn = l;
144     }
145 
146     public interface OnChangedListener {
147         abstract void OnChanged(boolean CheckState);
148     }
149 
150     public void setCheck(boolean isChecked) {
151         this.isChecked = isChecked;
152         NowChoose = isChecked;
153     }
154 
155     @Override
156     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
157 
158         int measuredHeight = measureHeight(heightMeasureSpec);
159         int measuredWidth = measureWidth(widthMeasureSpec);
160         setMeasuredDimension(measuredWidth, measuredHeight);
161     }
162 
163     private int measureHeight(int measureSpec) {
164 
165         /*int specMode = MeasureSpec.getMode(measureSpec);
166         int specSize = MeasureSpec.getSize(measureSpec);
167 
168         // Default size if no limits are specified.
169 
170         int result = 500;
171         if (specMode == MeasureSpec.AT_MOST){
172             // Calculate the ideal size of your
173             // control within this maximum size.
174             // If your control fills the available
175             // space return the outer bound.
176 
177             result = specSize;
178         } else if (specMode == MeasureSpec.EXACTLY){
179             // If your control can fit within these bounds return that value.
180             result = specSize;
181         }*/
182         return bg_on.getHeight();
183     }
184 
185     private int measureWidth(int measureSpec) {
186 
187         /*int specMode = MeasureSpec.getMode(measureSpec);
188         int specSize = MeasureSpec.getSize(measureSpec);
189 
190         // Default size if no limits are specified.
191         int result = 500;
192         if (specMode == MeasureSpec.AT_MOST){
193             // Calculate the ideal size of your control
194             // within this maximum size.
195             // If your control fills the available space
196             // return the outer bound.
197             result = specSize;
198         } else if (specMode == MeasureSpec.EXACTLY){
199             // If your control can fit within these bounds return that value.
200             result = specSize;
201         }*/
202         return bg_on.getWidth();
203     }
204 }

代码比较简单,而且注释比较详细。

说一些几个问题:

1. onTouch()方法中得到的event.getX()和event.getY()是什么值?取值范围是多少?

    刚开始我以为不管咱们的SlipButton放在什么位置,得到的event.getX()值因该是相对屏幕的坐标值,~~其实是错误的,event.getX()只有你的触摸点在当前SlipButton view的布局范围之内才会取到值的。但是值的范围可不仅仅是你的SlipButton view的大小哦,因为一旦你的触摸点在view范围之内触摸到,那么触摸点就可以移到View之外的任何地方了,所以取值范围应该是全屏哦,因此我们在代码里做了如下判断:

1 if (event.getX() > bg_on.getWidth()
2              || event.getY() > bg_on.getHeight()) {
3      return false;
4 }

2. measureWidth()和measureHeight()为什么会返回一个固定值?

    首先根据用途,我们自定义的SlipButton View根本没有必要去由调用者调整大小,因为这个ToggleButton本身就是起到开关作用的,在应用中应该是一致的,所以我让这两个方法返回固定值。关于onMeasure()方法根详细的描述,请看我的另一篇文章:http://www.cnblogs.com/wlrhnh/p/3479928.html

下载源码,请猛戳这里。

 posted on 2013-12-28 17:49  wlrhnh  阅读(1430)  评论(0编辑  收藏  举报