自定义控件,开关左右滑动
自定义控件一般的思路都是根据图片,自己绘制相应的控件
布局文件
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:paddingBottom="@dimen/activity_vertical_margin" 6 android:paddingLeft="@dimen/activity_horizontal_margin" 7 android:paddingRight="@dimen/activity_horizontal_margin" 8 android:paddingTop="@dimen/activity_vertical_margin" 9 tools:context=".MainActivity" > 10 11 <com.itheima27.slidebutton.view.SlideButton 12 android:id="@+id/slidebutton" 13 android:layout_width="wrap_content" 14 android:layout_height="wrap_content" 15 android:layout_centerInParent="true" /> 16 17 </RelativeLayout>
1 import com.itheima27.slidebutton.R; 2 import com.itheima27.slidebutton.interf.OnToggleStateChangedListener; 3 4 import android.content.Context; 5 import android.graphics.Bitmap; 6 import android.graphics.BitmapFactory; 7 import android.graphics.Canvas; 8 import android.util.AttributeSet; 9 import android.view.MotionEvent; 10 import android.view.View; 11 12 public class SlideButton extends View { 13 14 private Bitmap switchBG; // 滑动开关的背景 15 private Bitmap slideButtonBG; // 滑动块的背景 16 private boolean currentState = false; // 开关当前的状态, 默认为: 关闭 17 private int currentX; // x轴的偏移量 18 private boolean isSliding = false; // 是否正在滑动中 19 private OnToggleStateChangedListener mListener; 20 21 public SlideButton(Context context, AttributeSet attrs) { 22 super(context, attrs); 23 24 initBitmap(); 25 } 26 27 /** 28 * 当测量当前控件的宽高时回调 29 */ 30 @Override 31 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 32 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 33 34 // 设置开关的宽和高 35 setMeasuredDimension(switchBG.getWidth(), switchBG.getHeight()); 36 } 37 38 /** 39 * 绘制当前控件的方法 40 */ 41 @Override 42 protected void onDraw(Canvas canvas) { 43 44 // 1. 把滑动开关的背景画到画布上 45 canvas.drawBitmap(switchBG, 0, 0, null); // 把背景平铺到控件上 46 47 // 2. 绘制滑动块显示的位置, 开或者关 48 49 if(isSliding) { 50 int left = currentX - (slideButtonBG.getWidth() / 2); 51 if(left < 0) { 52 left = 0; 53 } else if(left > switchBG.getWidth() - slideButtonBG.getWidth()) { 54 left = switchBG.getWidth() - slideButtonBG.getWidth(); 55 } 56 57 canvas.drawBitmap(slideButtonBG, left, 0, null); 58 } else { 59 if(currentState) { // 绘制开关为开的状态 60 canvas.drawBitmap(slideButtonBG, switchBG.getWidth() - slideButtonBG.getWidth(), 0, null); 61 } else { // 绘制开关为关的状态 62 canvas.drawBitmap(slideButtonBG, 0, 0, null); 63 } 64 } 65 super.onDraw(canvas); 66 } 67 68 /** 69 * 当产生触摸时间时回调此方法 70 */ 71 @Override 72 public boolean onTouchEvent(MotionEvent event) { 73 switch (event.getAction()) { 74 case MotionEvent.ACTION_DOWN: // 按下 75 currentX = (int) event.getX(); 76 isSliding = true; 77 break; 78 case MotionEvent.ACTION_MOVE: // 移动 79 currentX = (int) event.getX(); 80 break; 81 case MotionEvent.ACTION_UP: // 抬起 82 isSliding = false; 83 84 // 判断当前滑动块, 偏向于哪一边, 如果滑动块的中心点小于背景的中心点, 设置为关闭状态 85 86 int bgCenter = switchBG.getWidth() / 2; 87 88 boolean state = currentX > bgCenter; // 改变后的状态 89 90 // 调用用户的监听事件 91 if(state != currentState && mListener != null) { 92 mListener.onToggleStateChanged(state); 93 } 94 95 currentState = state; 96 break; 97 default: 98 break; 99 } 100 101 invalidate(); // 刷新当前控件, 会引起onDraw方法的调用 102 return true; 103 } 104 105 /** 106 * 初始化图片 107 */ 108 private void initBitmap() { 109 slideButtonBG = BitmapFactory.decodeResource(getResources(), R.drawable.slide_button_background); 110 switchBG = BitmapFactory.decodeResource(getResources(), R.drawable.switch_background); 111 } 112 113 /** 114 * 设置开关的状态 115 * @param b 116 */ 117 public void setToggleState(boolean b) { 118 currentState = b; 119 } 120 121 /** 122 * 设置开关状态改变的监听事件 123 * @param listener 124 */ 125 public void setOnToggleStateChangedListener(OnToggleStateChangedListener listener) { 126 this.mListener = listener; 127 } 128 }