自定义ToggleButton

来源:互联网 发布:张无忌萧峰 知乎 编辑:程序博客网 时间:2024/06/16 22:36

很久之前就想写博客对自己的过去进行总结,由于个人比较懒这一原因而导致一直都未开始。现在鼓起勇气,克服这一懒惰心理开始写下第一篇博文。另外个人也是技术比较差,有什么写得不够好,不够详细的请各位同学多多指出,我将逐一改正。
好了,下面开始我们的自定义ToggleButton。那么我们先上图这里写图片描述
首先ToggleButton这个view控件由一张可拖动,可点击的小圆点和背景图组成。
上代码: 那么我们开始代码实战,逐一解析

package com.example.togglebutton;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Paint;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.View.OnClickListener;public class MyToggleButton extends View implements OnClickListener {    // 背景图    private Bitmap backgroundBitmap;    // 拖动的button    private Bitmap slideBtn;    private Paint paint;    private float slideBtn_left;    // slideBtn的状态    private boolean currState = false;    // 是否为拖动状态    private boolean isDrag = false;    public MyToggleButton(Context context) {        super(context);    }    public MyToggleButton(Context context, AttributeSet attrs) {        super(context, attrs);        initView();        initData();        initListener();    }    private void initView() {        backgroundBitmap = BitmapFactory.decodeResource(getResources(),                R.drawable.radio_i);        slideBtn = BitmapFactory.decodeResource(getResources(),                R.drawable.radio_slider_big);    }    private void initData() {        paint = new Paint();        paint.setAntiAlias(true);    }    private void initListener() {        setOnClickListener(this);    }    @Override    /**     * 设置view的测量值     */    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        setMeasuredDimension(backgroundBitmap.getWidth(),                backgroundBitmap.getHeight());    }    @Override    protected void onDraw(Canvas canvas) {        // draw背景        canvas.drawBitmap(backgroundBitmap, 0, 0, paint);        // draw拖动的按钮        canvas.drawBitmap(slideBtn, slideBtn_left, 2, paint);    }    @Override    /**     * 完整的一次down和up就是onclick事件     */    public void onClick(View v) {        if (!isDrag) {            currState = !currState;            flushState();        }    }    private int firstX;    private int lastX;    @Override    public boolean onTouchEvent(MotionEvent event) {        super.onTouchEvent(event);        switch (event.getAction()) {        case MotionEvent.ACTION_DOWN:            firstX = (int) event.getX();            isDrag = false;            break;        case MotionEvent.ACTION_MOVE:            lastX = (int) event.getX();            int distance = (int) (lastX - firstX);            if (Math.abs(distance) > 5) {// 如果移动距离超过5,则认为拖动了按钮                isDrag = true;            }            slideBtn_left = slideBtn_left + distance;            firstX = lastX;            break;        case MotionEvent.ACTION_UP:// 不管是onclick还是拖动都会触发up事件,所以在这里设置view的最终状态即可            if (isDrag) {                int maxLeft = backgroundBitmap.getWidth() - slideBtn.getWidth();                if (slideBtn_left > maxLeft / 2) {// 如果拖动的距离超过可拖动距离的一半                    currState = true;                } else {                    currState = false;                }                flushState();            }            break;        }        // move与up事件时刷新view        refreshView();        return true;    }    private void flushState() {        if (currState) {            slideBtn_left = backgroundBitmap.getWidth() - slideBtn.getWidth();        } else {            slideBtn_left = 0;        }        refreshView();        switchChangedListener.currState(this, currState);    }    private void refreshView() {        int maxLeft = backgroundBitmap.getWidth() - slideBtn.getWidth();        slideBtn_left = (slideBtn_left > 0) ? slideBtn_left : 0;        slideBtn_left = (slideBtn_left < maxLeft) ? slideBtn_left : maxLeft;        invalidate();    }    private MySwitchChangedListener switchChangedListener;    public interface MySwitchChangedListener {        void currState(View view, boolean state);    }    // 注册回调    public void setOnSwitchChangedListener(            MySwitchChangedListener switchChangedListener) {        this.switchChangedListener = switchChangedListener;    }}

ToggleButton使用时就是可点击,可拖动。
那么我们先在构造方法中初始化2张图,再初始化画笔paint,再对该view(ToggleButton)注册单击事件,仿照SDK原生的togglebutton,再复写onTouchEvent方法监听3种事件down,move,up。

首先draw背景图是不变的,我们只需要draw小圆点的位置

onclick时,比较简单,小圆点要么在整个view的最左边,要么在最右边。关键是这个draw图的距离 算好 即可。

捕捉移动事件:
down时,我们只需要记录初始时的X坐标,以及设置为非拖动状态。
move时,如果移动的距离超过5我们则认为拖动了小圆点,获取拖动的距离再从新绘制一遍view即可,设置为拖动状态。
up时,如果触发过move事件则不是onclick事件,注意:一次onclick就是完整的一次down和up组成,中间不包含move事件。onclick事件这个是比较好绘制的,如果触发过move时可能有点困难,这里可以取的distance其实是背景图的width减去小圆点的width这段距离,如上图。当拖动的距离超过这段距离的一半时,我们就在up这边直接设置小圆点到view的最左边或者最右边。

好了,其实就那么多东西了,还有就是在添加一个回调接口返回开关的状态。回调也即是设计模式中的观察者模式,在Android中很多地方都有用到,这个是必须要掌握的。

最后在xml布局文件中引用该view

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent" >    <com.example.togglebutton.MyToggleButton        android:id="@+id/toggle"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_centerInParent="true"        android:text="开关状态" /></RelativeLayout>

还需要在Activity中注册togglebutton的切换监听
这里写图片描述
第一次写文章,文章写得很丑,很多功能都还不知道,以后再慢慢改进。今天就到这了!

源码点击下载

0 0