开关案例
- 代码实现步骤
- [1]先在构造方法里面获取2张背景图片的宽和高
public ToggleView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);tbg = BitmapFactory.decodeResource(getResources(), R.drawable.toogle_background);sbg = BitmapFactory.decodeResource(getResources(), R.drawable.toogle_slidebg);slideMax = tbg.getWidth() - sbg.getWidth();String namespace = "http://schemas.android.com/apk/res-auto";boolean isOpen = attrs.getAttributeBooleanValue(namespace, "state", false);setOpenState(isOpen);if (state) {toLeft = slideMax;} else {toLeft = 0;}}
[2]重写onMeasure方法对当前view进行测量 当前view的宽高和toogleBg 一样
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {setMeasuredDimension(tbg.getWidth(), tbg.getHeight());}
[3]重写onDraw方法往当前的view上画内容 其实就是画图片
@Overrideprotected void onDraw(Canvas canvas) {canvas.drawBitmap(tbg, 0, 0, null);canvas.drawBitmap(sbg, toLeft, 0, null);if (isUp) {isUp = false;boolean isOpenTemp = toLeft > 0;if (isOpenTemp != state && listener != null) {listener.setState(isOpenTemp);state = isOpenTemp;}}}
[4]给开关定义监听事件 具体什么时候出发回调事件:
public void setOnStateListener(OnStateListener listener) {this.listener = listener;}public interface OnStateListener {void setState(boolean isOpen);}
[5]处理滑动块滑动的逻辑 重写onTouchEvent方法 处理手指按下和移动的逻辑
@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN://按下的距离downX = event.getX();break;case MotionEvent.ACTION_MOVE:endX = event.getX();moveX = endX - downX;toLeft = toLeft + moveX;if (toLeft <= 0) {toLeft = 0;}if (toLeft >= slideMax) {toLeft = slideMax;}downX = endX;break;case MotionEvent.ACTION_UP:isUp = true;float tHalf = tbg.getWidth() / 2;float sHalf = toLeft + sbg.getWidth() / 2;if (tHalf > sHalf) {toLeft = 0;} else {toLeft = slideMax;}break;}invalidate();return true;}
[6]处理手指抬起的业务逻辑
case MotionEvent.ACTION_UP:isUp = true;float tHalf = tbg.getWidth() / 2;float sHalf = toLeft + sbg.getWidth() / 2;if (tHalf > sHalf) {toLeft = 0;} else {toLeft = slideMax;}break;
[7]实现开关的功能.
if (isUp) {isUp = false;boolean isOpenTemp = toLeft > 0;if (isOpenTemp != state && listener != null) {listener.setState(isOpenTemp);state = isOpenTemp;}}
[8]自定义开关的属性
8.1)在res下定义一个attrs文件
<?xml version="1.0" encoding="utf-8"?> <resources><declare-styleable name="ToggleView"><attr name="state" format="boolean" /></declare-styleable> </resources>
8.2)自己声明一个命名空间.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:toogle="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ngyb.choose.ToggleViewandroid:id="@+id/tv"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="center"toogle:state="true" /> </LinearLayout>
8.3)在构造方法里面获取我们声明的属性值
String namespace = "http://schemas.android.com/apk/res-auto";boolean isOpen = attrs.getAttributeBooleanValue(namespace, "state", false);
8.4)更新开关的状态
public void setOpenState(boolean openState) {isUp = true;this.state = openState;}
https://github.com/nangongyibin7219/Android_OnOff