继承View自定义开关控件

自定义开关按钮

简单示意图

自定义开关

  • 采用先使用后创建的思路
    现在主Activity 中创建方法,比如状态开关,监听器,等等
myToggleButton.setOnStateChangeListener(new MyToggleButton.OnStateChangeListener() {}
  • 为方便使用自定义属性在values文件目录下创建attrs.xml
    设置attrs.xml文件在values中
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyToggleButton">
        <attr name="switchState" format="boolean"></attr>
        <attr name="slideIcon" format="reference"></attr>
        <attr name="slideBackground" format="reference"></attr>
    </declare-styleable>

</resources>

在带有attrs参数的构造方法中调用

   /**
     * 重写带属性的方法,使用在布局文件中
     */
    public MyToggleButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        //已在xml中配置,这里是获取图片资源bitmap
        int slide_iconResId = attrs.getAttributeResourceValue("http://schemas.android.com/apk/res-auto", "slideIcon", -1);
        int slide_backgroundResId = attrs.getAttributeResourceValue("http://schemas.android.com/apk/res-auto", "slideBackground", -1);
        switchState = attrs.getAttributeBooleanValue("http://schemas.android.com/apk/res-auto", "switchState", true);
        slide_background = BitmapFactory.decodeResource(getResources(), slide_backgroundResId);
        //获取宽高信息
        slide_backgroundWidth = slide_background.getWidth();
        slide_backgroundHeight = slide_background.getHeight();
        slide_icon = BitmapFactory.decodeResource(getResources(), slide_iconResId);
        slide_iconWidth = slide_icon.getWidth();
        slide_iconHeight = slide_icon.getHeight();
    }
  • 实现状态改变监听
/**
     * 创建监听器
     *
     * @param listener 回调接口
     */
    public void setOnStateChangeListener(OnStateChangeListener listener) {
        //类似与OnClickListener()方法中的回调方法,具体可看View中的点击监听的源码
        if (mOnStateChangeListener == null) {
            mOnStateChangeListener = listener;
        }

    }
  • 继承OnMeature 对背景进行测量宽高,
  • setMeasuredDimension(measureWidth, measureHeight);进行设定控件宽高
 /**
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int measureWidth = slide_backgroundWidth;
        int measureHeight = slide_backgroundHeight;
        offLeftTop = slide_backgroundWidth - slide_iconWidth;
        left = offLeftTop;
        setMeasuredDimension(measureWidth, measureHeight);
    }
  • 继承OnDraw,使用canvas.drawBitmap();画出控件样式
 /**
     * 初始化画板
     *
     * @param canvas 画板
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(slide_background, 0, 0, null);
        //根据设定状态,画出初始化开关状态;
        canvas.drawBitmap(slide_icon, left, 0, null);
    }

* 重写OnTouchEvent(),记录手指移动的方式并对上边的按钮进行赋值

简单分析
简单分析

  /**
     * 设定按钮图片的滑动事件
     *
     * @param event
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN://手指按下事件
                down_dot = event.getX();
                changeSwitchState();//触发状态改变方法
                return true;//将事件消耗掉
            case MotionEvent.ACTION_UP://手指抬起事件
                float up_dot = event.getX();//手指抬起的点
                if (up_dot < slide_backgroundWidth / 2) {
                    switchState = false;
                    left = 0;
                } else {
                    switchState = true;
                    left = offLeftTop;
                }
                /**
                 * 状态改变的监听事件
                 * @param switchState 监听到状态改变事件
                 */
                mOnStateChangeListener.OnStateChange(switchState);
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE://手指移动事件
                float move_dot = event.getX();//手指移动的点
                float move2down = move_dot - down_dot;//手指移动点相比于初次按下的点
                float lefttopIcon = move_dot - slide_iconWidth / 2;
                if (move_dot < slide_iconWidth / 2) {
                } else if (move_dot > (slide_backgroundWidth - slide_iconWidth / 2)) {
                } else {
                    if (move2down > 0) {
                        if (lefttopIcon >= offLeftTop) {
                            left = offLeftTop;
                        } else {
                            left = (int) lefttopIcon;
                        }
                    } else {
                        if (lefttopIcon <= 0) {
                            left = 0;
                        } else {
                            left = (int) lefttopIcon;
                        }
                    }
                }
                invalidate();
                return true;
        }
        return super.onTouchEvent(event);
    }
  • 创建回调接口,实现开关状态改变的监听。
 /**
     * 创建回调接口
     */
    public interface OnStateChangeListener {
        void OnStateChange(boolean state);
    }
/**
     * 根据点击下的位置判断,修改开关状态
     */
    private void changeSwitchState() {

        if (switchState) {//如果是开启状态
            if (down_dot < slide_backgroundWidth / 2) {
                left = 0;//设定按钮画布的初始点为0
                switchState = !switchState;
            }
        } else {//如果是关闭状态
            if (down_dot > slide_backgroundWidth / 2) {
                left = offLeftTop;//设定按钮画布的初始点为offLeftTop
                switchState = !switchState;
            }
        }
        invalidate();//通知画布,重新画布局
    }

    /**
     * 自定义开关开启的状态
     *
     * @param switchState 开关状态
     */
    public void setSwitchState(boolean switchState) {
        this.switchState = switchState;
        invalidate();
    }

源码部分

package com.oblivion.viewUI;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by oblivion on 2016/10/22.
 */
public class MyToggleButton extends View {
    /**
     * 根据位图工厂获取开关背景Bitmap
     */
    private Bitmap slide_background;
    /**
     * 根据位图工厂获取开关按钮Bitmap
     */
    private Bitmap slide_icon;
    /**
     * 开关背景的长度
     */
    private int slide_backgroundWidth;
    /**
     * 开关背景的高度
     */
    private int slide_backgroundHeight;
    /**
     * 开关按钮的宽度
     */
    private int slide_iconWidth;
    /**
     * 开关按钮的高度
     */
    private int slide_iconHeight;
    /**
     * 设定初始化开关状态
     */
    private boolean switchState;
    /**
     * 获取所在图层范围的点击下的X坐标
     */
    private float down_dot;
    /**
     * 开关按钮在画布上X的起始画点
     */
    private int left;
    /**
     * 开关按钮在画布上Y的起始画点
     */
    private int top;
    /**
     * 抽取按钮在最右边的起始点
     */
    private int offLeftTop;
    /**
     * 定义回调接口
     */
    private OnStateChangeListener mOnStateChangeListener;

    /**
     * 重写带属性的方法,使用在布局文件中
     */
    public MyToggleButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        int slide_iconResId = attrs.getAttributeResourceValue("http://schemas.android.com/apk/res-auto", "slideIcon", -1);
        int slide_backgroundResId = attrs.getAttributeResourceValue("http://schemas.android.com/apk/res-auto", "slideBackground", -1);
        switchState = attrs.getAttributeBooleanValue("http://schemas.android.com/apk/res-auto", "switchState", true);
        slide_background = BitmapFactory.decodeResource(getResources(), slide_backgroundResId);
        slide_backgroundWidth = slide_background.getWidth();
        slide_backgroundHeight = slide_background.getHeight();
        slide_icon = BitmapFactory.decodeResource(getResources(), slide_iconResId);
        slide_iconWidth = slide_icon.getWidth();
        slide_iconHeight = slide_icon.getHeight();
    }

    /**
     * 重写new 使用的构造方法
     */
    public MyToggleButton(Context context) {
        super(context);
    }

    /**
     * 获取开关背景资源
     *
     * @param slide_backgroundResId 开关背景
     *//*
    public void setSlideBackground(int slide_backgroundResId) {
        slide_background = BitmapFactory.decodeResource(getResources(), slide_backgroundResId);
        slide_backgroundWidth = slide_background.getWidth();
        slide_backgroundHeight = slide_background.getHeight();
    }

    *//**
     * 获取开关按钮资源
     *
     * @param slide_iconResId 开关按钮资源
     *//*
    public void setSlideIcon(int slide_iconResId) {
        slide_icon = BitmapFactory.decodeResource(getResources(), slide_iconResId);
        slide_iconWidth = slide_icon.getWidth();
        slide_iconHeight = slide_icon.getHeight();
    }
*/

    /**
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int measureWidth = slide_backgroundWidth;
        int measureHeight = slide_backgroundHeight;
        offLeftTop = slide_backgroundWidth - slide_iconWidth;
        left = offLeftTop;
        setMeasuredDimension(measureWidth, measureHeight);
    }


    /**
     * 初始化画板
     *
     * @param canvas 画板
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(slide_background, 0, 0, null);
        //根据设定状态,画出初始化开关状态;
        canvas.drawBitmap(slide_icon, left, 0, null);
    }


    /**
     * 设定按钮图片的滑动事件
     *
     * @param event
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN://手指按下事件
                down_dot = event.getX();
                changeSwitchState();//触发状态改变方法
                return true;//将事件消耗掉
            case MotionEvent.ACTION_UP://手指抬起事件
                float up_dot = event.getX();//手指抬起的点
                if (up_dot < slide_backgroundWidth / 2) {
                    switchState = false;
                    left = 0;
                } else {
                    switchState = true;
                    left = offLeftTop;
                }
                /**
                 * 状态改变的监听事件
                 * @param switchState 监听到状态改变事件
                 */
                mOnStateChangeListener.OnStateChange(switchState);
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE://手指移动事件
                float move_dot = event.getX();//手指移动的点
                float move2down = move_dot - down_dot;//手指移动点相比于初次按下的点
                float lefttopIcon = move_dot - slide_iconWidth / 2;
                if (move_dot < slide_iconWidth / 2) {
                } else if (move_dot > (slide_backgroundWidth - slide_iconWidth / 2)) {
                } else {
                    if (move2down > 0) {
                        if (lefttopIcon >= offLeftTop) {
                            left = offLeftTop;
                        } else {
                            left = (int) lefttopIcon;
                        }
                    } else {
                        if (lefttopIcon <= 0) {
                            left = 0;
                        } else {
                            left = (int) lefttopIcon;
                        }
                    }
                }
                invalidate();
                return true;
        }
        return super.onTouchEvent(event);
    }

    /**
     * 根据点击下的位置判断,修改开关状态
     */
    private void changeSwitchState() {

        if (switchState) {//如果是开启状态
            if (down_dot < slide_backgroundWidth / 2) {
                left = 0;//设定按钮画布的初始点为0
                switchState = !switchState;
            }
        } else {//如果是关闭状态
            if (down_dot > slide_backgroundWidth / 2) {
                left = offLeftTop;//设定按钮画布的初始点为offLeftTop
                switchState = !switchState;
            }
        }
        invalidate();//通知画布,重新画布局
    }

    /**
     * 自定义开关开启的状态
     *
     * @param switchState 开关状态
     */
    public void setSwitchState(boolean switchState) {
        this.switchState = switchState;
        invalidate();
    }

    /**
     * 创建回调接口
     */
    public interface OnStateChangeListener {
        void OnStateChange(boolean state);
    }

    /**
     * 创建监听器
     *
     * @param listener 回调接口
     */
    public void setOnStateChangeListener(OnStateChangeListener listener) {
        //类似与OnClickListener()方法中的回调方法,具体可看View中的点击监听的源码
        if (mOnStateChangeListener == null) {
            mOnStateChangeListener = listener;
        }

    }
}

github源码地址

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值