1 @Override 2 public void onClick(View v) { 3 if(!isDrop){ 4 if(toggleState){ 5 slideLeft = 0; 6 toggleState = false; 7 } 8 else{ 9 slideLeft = slideLeftMax; 10 toggleState = true; 11 } 12 13 //让界面无效,onDraw会重新调用 14 invalidate(); 15 } 16 }
int lastX; 上一次坐标
1 public boolean onTouchEvent(MotionEvent event) { 2 super.onTouchEvent(event); 3 switch (event.getAction()) { 4 case MotionEvent.ACTION_DOWN: 5 //记录手指按下时的坐标 6 firstX = lastX = (int) event.getX(); 7 8 isDrop = false; //用户一按下就需要从新设置标记状态 9 10 break; 11 case MotionEvent.ACTION_MOVE: 12 int newX = (int) event.getX(); 13 14 //判断用户当前时点击还是滑动,如果手指移动的像素超过6,那么判定为滑动 15 if(Math.abs(newX - firstX) > 6){ 这里需要取绝对值 16 isDrop = true; 17 } 18 break; 19 case MotionEvent.ACTION_UP: 20 if(isDrop){ 21 逻辑代码.... 22 } 23 break; 24 } 25 flushView(); 26 return true; 27 }
public void onClick(View v) { if(!isDrop){ 逻辑代码..... } }
1 res/values/创建attrs.xml
2 一、在attrs.xml文件中声明属性,如:
3 <declare-styleable name="MyToggleBtn"> // 声名属性集的名称,即这些属性是属于哪个控件的。 4 <attr name="current_state" format="boolean"/> // 声名属性 current_state 格式为 boolean 类型 5 <attr name="slide_button" format="reference"/> // 声名属性 slide_button 格式为 reference 类型 6 </declare-styleable> 7 所有的format类型,详见注1:
8 二、在布局文件中使用:在使用之前必须声名命名空间,xmlns:heima="http://schemas.android.com/apk/res/com.itheima.mytogglebtn" 9 说明:xmlns 是XML name space 的缩写; 10 heima 可为任意写符 11 http://schemas.android.com/apk/res/ 此为android固定格式; 12 com.itheima.mytogglebtn 此应用的包名,如manifest配置文件中一致。
13 布局文件: 14 <com.itheima.mytogglebtn.MyToggleButton 15 xmlns:heima="http://schemas.android.com/apk/res/com.itheima.mytogglebtn" 16 android:layout_width="wrap_content" 17 android:layout_height="wrap_content" 18 heima:slide_button="@drawable/slide_button" />
19 三、在代码中对属性进行解析,主要代码:
20 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyToggleBtn); // 由attrs 获得 TypeArray
21 注1: 22 format 常用类型 23 reference 引用 24 color 颜色 25 boolean 布尔值 26 dimension 尺寸值 27 float 浮点值 28 integer 整型值 29 string 字符串 30 enum 枚举值
2 3 import android.annotation.SuppressLint; 4 import android.content.Context; 5 import android.content.res.TypedArray; 6 import android.graphics.Bitmap; 7 import android.graphics.BitmapFactory; 8 import android.graphics.Canvas; 9 import android.graphics.Paint; 10 import android.graphics.drawable.BitmapDrawable; 11 import android.util.AttributeSet; 12 import android.view.MotionEvent; 13 import android.view.View; 14 import android.view.View.OnClickListener; 15 16 17 public class MyToggleButton extends View implements OnClickListener { 18 19 private Bitmap slide_button; 20 private Bitmap switch_background; 21 int slideLeft = 0; 22 boolean toggleState = false; 23 int slideLeftMax; 24 int firstX; 25 int lastX; 26 boolean isDrop = false; 27 28 //AttributeSet:封装了布局文件中定义的属性 29 public MyToggleButton(Context context, AttributeSet attrs) { 30 super(context, attrs); 31 32 //获取属性的名字和值 33 // int count = attrs.getAttributeCount(); 34 // for (int i = 0; i < count; i++) { 35 // System.out.print(attrs.getAttributeName(i) + "; "); 36 // System.out.println(attrs.getAttributeValue(i)); 37 // } 38 39 //解析AttributeSet,返回一个TypedArray,此对象中封装了解析出来的属性 40 //arg1:期望解析出来的属性自定义的属性在R文件中有数组记录 int值 41 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyToggleBtn); 42 //取出解析好的属性值 43 BitmapDrawable bd1 = (BitmapDrawable) ta.getDrawable(R.styleable.MyToggleBtn_switch_bg); 44 BitmapDrawable bd2 = (BitmapDrawable) ta.getDrawable(R.styleable.MyToggleBtn_slide_bg); 45 //把BitmapDrawable中封装的图片以Bitmap形式返回 46 switch_background = bd1.getBitmap(); 47 slide_button = bd2.getBitmap(); 48 49 // slide_button = BitmapFactory.decodeResource(getResources(), R.drawable.slide_button); 50 // switch_background = BitmapFactory.decodeResource(getResources(), R.drawable.switch_background); 51 52 //算出两个图片的宽度差 53 slideLeftMax = switch_background.getWidth() - slide_button.getWidth(); 54 //给自己设置点击侦听,此时,这个组件就可以被点击了 55 setOnClickListener(this); 56 } 57 58 @Override 59 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 60 // super.onMeasure(widthMeasureSpec, heightMeasureSpec); 61 //指定组件宽高 62 setMeasuredDimension(switch_background.getWidth(), switch_background.getHeight()); 63 } 64 65 @Override 66 protected void onDraw(Canvas canvas) { 67 // TODO Auto-generated method stub 68 super.onDraw(canvas); 69 70 Paint paint = new Paint(); 71 canvas.drawBitmap(switch_background, 0, 0, paint); 72 canvas.drawBitmap(slide_button, slideLeft, 0, paint); 73 } 74 75 @Override 76 public void onClick(View v) { 77 if(!isDrop){ 78 if(toggleState){ 79 slideLeft = 0; 80 toggleState = false; 81 } 82 else{ 83 slideLeft = slideLeftMax; 84 toggleState = true; 85 } 86 87 //让界面无效,onDraw会重新调用 88 invalidate(); 89 } 90 } 91 92 //触摸事件,当这个组件被触摸,就会产生触摸事件 93 @Override 94 public boolean onTouchEvent(MotionEvent event) { 95 super.onTouchEvent(event); 96 switch (event.getAction()) { 97 case MotionEvent.ACTION_DOWN: 98 //记录手指按下时的坐标 99 firstX = lastX = (int) event.getX(); 100 isDrop = false; 101 break; 102 case MotionEvent.ACTION_MOVE: 103 int newX = (int) event.getX(); 104 //计算手指移动的像素 105 int offsetX = newX - lastX; 106 slideLeft += offsetX; 107 lastX = newX; 108 109 //判断用户当前时点击还是滑动,如果手指移动的像素超过6,那么判定为滑动 110 if(Math.abs(newX - firstX) > 6){ 111 isDrop = true; 112 } 113 break; 114 case MotionEvent.ACTION_UP: 115 if(isDrop){ 116 //获取手指抬起时的坐标,判断手指滑动的距离,如果距离大于开关长度的一半,那么就生效 117 int upX = (int) event.getX(); 118 if(upX - firstX >= slideLeftMax / 2){ 119 toggleState = true; 120 } 121 else if(firstX - upX >= slideLeftMax / 2){ 122 toggleState = false; 123 } 124 flushState(); 125 } 126 break; 127 128 } 129 flushView(); 130 return true; 131 } 132 133 private void flushState() { 134 if(toggleState) 135 slideLeft = slideLeftMax; 136 else 137 slideLeft = 0; 138 139 } 140 private void flushView() { 141 if(slideLeft < 0) 142 slideLeft = 0; 143 else if(slideLeft > slideLeftMax) 144 slideLeft = slideLeftMax; 145 invalidate(); 146 } 147 }
1 <RelativeLayout 2 xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:itheima="http://schemas.android.com/apk/res/com.itheima.custombutton" 4 xmlns:tools="http://schemas.android.com/tools" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent" 7 android:paddingBottom="@dimen/activity_vertical_margin" 8 android:paddingLeft="@dimen/activity_horizontal_margin" 9 android:paddingRight="@dimen/activity_horizontal_margin" 10 android:paddingTop="@dimen/activity_vertical_margin" 11 tools:context=".MainActivity" > 12 13 14 <com.itheima.custombutton.MyToggleButton 15 android:layout_width="wrap_content" 16 android:layout_height="wrap_content" 17 android:layout_centerInParent="true" 18 itheima:switch_bg="@drawable/switch_background" 19 itheima:slide_bg="@drawable/slide_button" 20 /> 21 22 </RelativeLayout>
1 <?xml version="1.0" encoding="utf-8"?> 2 <resources> 3 <declare-styleable name="MyToggleBtn"> 4 <attr name="switch_bg" format="reference"/> 5 <attr name="slide_bg" format="reference"/> 6 </declare-styleable> 7 </resources>