自定义ToggleButton

很久之前就想写博客对自己的过去进行总结,由于个人比较懒这一原因而导致一直都未开始。现在鼓起勇气,克服这一懒惰心理开始写下第一篇博文。另外个人也是技术比较差,有什么写得不够好,不够详细的请各位同学多多指出,我将逐一改正。
好了,下面开始我们的自定义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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值