自定义控件:滑动开关按钮

 

 1 <RelativeLayout 
 2     xmlns:android="http://schemas.android.com/apk/res/android"
 3     xmlns:tools="http://schemas.android.com/tools"
 4     android:layout_width="match_parent"
 5     android:layout_height="match_parent" >
 6 
 7     <com.example.testdemo.MyToggleButton
 8         android:id="@+id/my_toggle_btn"
 9         android:layout_width="wrap_content"
10         android:layout_height="wrap_content"
11         android:layout_centerHorizontal="true"
12         android:layout_centerVertical="true" />
13 
14 </RelativeLayout>
  1 package com.example.testdemo;
  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.Paint;
  8 import android.util.AttributeSet;
  9 import android.view.MotionEvent;
 10 import android.view.View;
 11 import android.view.View.OnClickListener;
 12 
 13 public class MyToggleButton extends View implements OnClickListener {
 14 
 15     // 做为背景的图片
 16     private Bitmap backgroundBitmap;
 17     // 可以滑动的图片
 18     private Bitmap slideBtn;
 19     private Paint paint;
 20     // 滑动按钮的左边届
 21     private float slideBtn_left;
 22     // down 事件时的x值
 23     private int firstX;
 24     // touch 事件的上一个x值
 25     private int lastX;
 26     // 当前开关的状态 true 为开
 27     private boolean currState = false;
 28     // 判断是否发生拖动, 如果拖动了,就不再响应 onclick 事件
 29     private boolean isDrag = false;
 30 
 31     /**
 32      * 在代码里面创建对象的时候,使用此构造方法
 33      */
 34     public MyToggleButton(Context context) {
 35         super(context);
 36         // TODO Auto-generated constructor stub
 37     }
 38 
 39     /**
 40      * 在布局文件中声名的view,创建时由系统自动调用。
 41      * 
 42      * @param context
 43      *            上下文对象
 44      * @param attrs
 45      *            属性集
 46      */
 47     public MyToggleButton(Context context, AttributeSet attrs) {
 48         super(context, attrs);
 49 
 50         initView();
 51     }
 52 
 53     /**
 54      * 初始化
 55      */
 56     private void initView() {
 57 
 58         // 初始化图片
 59         backgroundBitmap = BitmapFactory.decodeResource(getResources(),
 60                 R.drawable.switch_background);
 61         slideBtn = BitmapFactory.decodeResource(getResources(),
 62                 R.drawable.slide_button);
 63 
 64         // 初始化 画笔
 65         paint = new Paint();
 66         paint.setAntiAlias(true); // 打开抗矩齿
 67 
 68         // 添加onclick事件监听
 69         setOnClickListener(this);
 70     }
 71 
 72     /*
 73      * view 对象显示的屏幕上,有几个重要步骤: 
 74      * 1、构造方法 创建 对象。 
 75      * 2、测量view的大小。 onMeasure(int,int);
 76      * 3、确定view的位置 ,view自身有一些建议权,决定权在 父view手中。 onLayout(); 
 77      * 4、绘制 view 的内容 。
 78      * onDraw(Canvas)
 79      */
 80 
 81     @Override
 82     /**
 83      * 测量尺寸时的回调方法 
 84      */
 85     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 86         // super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 87         // 设置当前view的大小 width :view的宽度 height :view的高度 (单位:像素)
 88         setMeasuredDimension(backgroundBitmap.getWidth(),
 89                 backgroundBitmap.getHeight());
 90     }
 91 
 92     // 确定位置的时候调用此方法
 93     // 自定义view的时候,作用不大
 94     // @Override
 95     // protected void onLayout(boolean changed, int left, int top, int right,
 96     // int bottom) {
 97     // super.onLayout(changed, left, top, right, bottom);
 98     // }
 99 
100     @Override
101     /**
102      * 绘制当前view的内容
103      */
104     protected void onDraw(Canvas canvas) {
105         // super.onDraw(canvas);
106 
107         // 绘制 背景
108         /*
109          * backgroundBitmap 要绘制的图片 left 图片的左边届 top 图片的上边届 paint 绘制图片要使用的画笔
110          */
111         canvas.drawBitmap(backgroundBitmap, 0, 0, paint);
112 
113         // 绘制 可滑动的按钮
114         canvas.drawBitmap(slideBtn, slideBtn_left, 0, paint);
115     }
116 
117 
118     @Override
119     /**
120      * onclick 事件在View.onTouchEvent 中被解析。
121      * 系统对onclick 事件的解析,过于简陋,只要有down 事件  up 事件,
122      * 系统即认为 发生了click 事件
123      */
124     public void onClick(View v) {
125         // 如果没有拖动,才执行改变状态的动作
126         if (!isDrag) {
127             currState = !currState;
128             flushState();
129         }
130     }
131 
132     @Override
133     public boolean onTouchEvent(MotionEvent event) {
134         super.onTouchEvent(event);
135 
136         switch (event.getAction()) {
137         case MotionEvent.ACTION_DOWN:
138             firstX = lastX = (int) event.getX();
139             isDrag = false;
140 
141             break;
142         case MotionEvent.ACTION_MOVE:
143 
144             // 判断是否发生拖动
145             if (Math.abs(event.getX() - firstX) > 5) {
146                 isDrag = true;
147             }
148 
149             // 计算 手指在屏幕上移动的距离
150             int dis = (int) (event.getX() - lastX);
151 
152             // 将本次的位置 设置给lastX
153             lastX = (int) event.getX();
154 
155             // 根据手指移动的距离,改变slideBtn_left 的值
156             slideBtn_left = slideBtn_left + dis;
157             break;
158         case MotionEvent.ACTION_UP:
160             // 在发生拖动的情况下,根据最后的位置,判断当前开关的状态
161             if (isDrag) {
162                 // alideBtn 左边界最大值
163                 int maxLeft = backgroundBitmap.getWidth() - slideBtn.getWidth();
165                 /*
166                  * 根据 slideBtn_left 判断,当前应是什么状态
167                  */
168                 if (slideBtn_left > maxLeft / 2) { // 此时应为 打开的状态
169                     currState = true;
170                 } else {
171                     currState = false;
172                 }
174                 flushState();
175             }
176             break;
177         }
179         flushView();
181         return true;
182     }
183 
184     /**
185      * 刷新当前状态
186      */
187     private void flushState() {
188         if (currState) {
189             slideBtn_left = backgroundBitmap.getWidth() - slideBtn.getWidth();
190         } else {
191             slideBtn_left = 0;
192         }
194         flushView();
195     }
196 
197     /**
198      * 刷新当前视力
199      */
200     private void flushView() {
201         /*
202          * 对 slideBtn_left 的值进行判断 ,确保其在合理的位置 即 0<=slideBtn_left <= maxLeft
203          */
205         int maxLeft = backgroundBitmap.getWidth() - slideBtn.getWidth(); 207 
208         // 确保 slideBtn_left >= 0
209         slideBtn_left = (slideBtn_left > 0) ? slideBtn_left : 0;
210 
211         // 确保 slideBtn_left <=maxLeft
212         slideBtn_left = (slideBtn_left < maxLeft) ? slideBtn_left : maxLeft;
213 
214         /*
215          * 刷新当前视图 导致 执行onDraw执行
216          */
217         invalidate();
218     }
219 
220 }

 DEMO下载地址:http://pan.baidu.com/s/1qWjXEhQ

原文地址:https://www.cnblogs.com/androidsj/p/3995307.html