Android自定义开关

来源:互联网 发布:淘宝笔记本排行榜 编辑:程序博客网 时间:2024/06/15 23:13

最近在学习自定义view,感觉写业务代码对技术的提高实在有限,就琢磨每天 必须要多学点东西了,我的规划是自定义view、jni,之后再往framework层走,先拓展技术栈,再精进。

不多说先看效果图

这里写图片描述

一:需求分析:首先我们来明确一下需求,有两种方式来控制这个开关,一种是点击,即可切换开关,另一种是通过滑动来控制,这样比起我们一般情况下直接用个图片选择器体验会好一些。

二:实现思路:其实思路还是很清晰的,大的步骤的话就两步

  • 1:将view绘制出来,其实是两张图片,一张是开关的背景,在上面有一个滑块,滑块在最左侧时为关闭状态,在最右侧时为打开的状态。

  • 2:给view设置点击事件和滑动事件,逻辑还是比较清晰的,当点击时开关的状态切换,当滑动时,根据滑动的位置来确定当前应该是开的状态还是关的状态

三:代码分析:

代码分为三个部分:初始化、绘制,点击及触摸事件处理

  • 一 :初始化,代码如下
/**     * 注意构造方法,一个参数用于实例化,两个参数用于在布局文件中使用时调用,三个用于自定义style时使用,这里我们用两个参数的     *     * @param context     */    public MyToggleButton(Context context, AttributeSet attrs) {        super(context, attrs);        init(context);    }    public void init(Context context) {        paint = new Paint();        paint.setAntiAlias(true);        backgroundBitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.switch_background);        slidingBitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.slide_button);        maxLeft = backgroundBitmap.getWidth() - slidingBitmap.getWidth();        //设置点击事件        setOnClickListener(this);    }
  • 二:绘制流程:onMeasure方法,用于测量控件的宽高,onLayout用于摆放控件的位置,一般自定义的viewGroup才用得到onDraw方法,将控件在屏幕中绘制出来,这里我们只用得到onMeasure和onDraw,代码如下:
 /**     * 指定view的大小     *     * @param widthMeasureSpec     * @param heightMeasureSpec     */    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        setMeasuredDimension(backgroundBitmap.getWidth(), backgroundBitmap.getHeight());    }    /**     * 具体的绘制方法     *     * @param canvas     */    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        canvas.drawBitmap(backgroundBitmap, 0, 0, paint);        canvas.drawBitmap(slidingBitmap, slideLeft, 0, paint);    }
  • 三:点击及触摸事件的处理,事件完成之后要调用 invalidate()方法,会导致onDraw方法重新执行,今儿从新绘制view,具体代码如下:
 /**     * 点击事件方法的具体实现     *     * @param v     */    @Override    public void onClick(View v) {        if (isClickEnable) {            isOpen = !isOpen;            flushView(isOpen);        }    }    /**     * 滑动事件的具体实现     *     * @param event     * @return     */    @Override    public boolean onTouchEvent(MotionEvent event) {        //执行父类的方法,否则,onclick点击方法就不起作用        super.onTouchEvent(event);        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                initX = startX = (int) event.getX();                isClickEnable=true;                break;            case MotionEvent.ACTION_MOVE:                endX = (int) event.getX();                lastX = (endX - startX);                slideLeft += lastX;                if (slideLeft > maxLeft) {                    slideLeft = maxLeft;                } else if (slideLeft < 0) {                    slideLeft = 0;                }                invalidate();                startX = (int) event.getX();                if (Math.abs(endX - initX) > 5) {                    isClickEnable = false;                }                break;            case MotionEvent.ACTION_UP:                if (!isClickEnable) {                    if (slideLeft > maxLeft / 2) {                        isOpen = true;                    } else {                        isOpen = false;                    }                    flushView(isOpen);                    invalidate();                }                break;        }        return true;    }    /**     * 刷新控件,归位,是开还是关     */    public void flushView(boolean isOpen) {        if (isOpen) {            slideLeft = maxLeft;        } else {            slideLeft = 0;        }        invalidate();    }

完整代码如下:

/** * Created by ${HMC} on 2017/4/4.实现的效果就是点击或者滑动都可以对开关进行控制 * 自定义view的绘制流程: * 首先走构造方法,然后如下 * ①:onMeasure方法,用于测量控件的宽高 * ②onLayout用于摆放控件的位置,一般自定义的viewGroup才用得到 * ③onDraw方法,将控件在屏幕中绘制出来 * <p> * 思路:先将view绘制出来,在做逻辑处理,比如滑动等 */public class MyToggleButton extends View implements View.OnClickListener {    Bitmap backgroundBitmap;    Bitmap slidingBitmap;    Paint paint;    private int slideLeft;    private int maxLeft;    //滑动时的坐标记录    int startX;    int endX;    //移动的距离    int lastX;    //最开始的距离    int initX;    //开关是否打开    boolean isOpen;    //点击事件是否可用    boolean isClickEnable = true;    /**     * 两个用于在布局文件中使用时调用,三个用于自定义style时使用     *     * @param context     */    public MyToggleButton(Context context, AttributeSet attrs) {        super(context, attrs);        init(context);    }    public void init(Context context) {        paint = new Paint();        paint.setAntiAlias(true);        backgroundBitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.switch_background);        slidingBitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.slide_button);        maxLeft = backgroundBitmap.getWidth() - slidingBitmap.getWidth();        //设置点击事件        setOnClickListener(this);    }    /**     * 指定view的大小     *     * @param widthMeasureSpec     * @param heightMeasureSpec     */    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        setMeasuredDimension(backgroundBitmap.getWidth(), backgroundBitmap.getHeight());    }    /**     * 具体的绘制方法     *     * @param canvas     */    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        canvas.drawBitmap(backgroundBitmap, 0, 0, paint);        canvas.drawBitmap(slidingBitmap, slideLeft, 0, paint);    }    /**     * 点击事件方法的具体实现     *     * @param v     */    @Override    public void onClick(View v) {        if (isClickEnable) {            isOpen = !isOpen;            flushView(isOpen);        }    }    /**     * 滑动事件的具体实现     *     * @param event     * @return     */    @Override    public boolean onTouchEvent(MotionEvent event) {        //执行父类的方法,否则,onclick点击方法就不起作用        super.onTouchEvent(event);        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                initX = startX = (int) event.getX();                isClickEnable=true;                break;            case MotionEvent.ACTION_MOVE:                endX = (int) event.getX();                lastX = (endX - startX);                slideLeft += lastX;                if (slideLeft > maxLeft) {                    slideLeft = maxLeft;                } else if (slideLeft < 0) {                    slideLeft = 0;                }                invalidate();                startX = (int) event.getX();                if (Math.abs(endX - initX) > 5) {                    isClickEnable = false;                }                break;            case MotionEvent.ACTION_UP:                if (!isClickEnable) {                    if (slideLeft > maxLeft / 2) {                        isOpen = true;                    } else {                        isOpen = false;                    }                    flushView(isOpen);                    invalidate();                }                break;        }        return true;    }
0 0
原创粉丝点击