Android 自定义ToggleButton

Android自定义ToggleButton

1.需求

在项目需求中,可能需要自定义开关按钮,于是本人就根据网上的教程写了个符合自己需求的按钮
首先看一下要实现的效果:有4中图片的切换效果,点击切换开关状态,还要求支持滑动切换。
这里写图片描述

2.解决思路

写个MyToggleButton类,继承自View,重写onDraw,onClick,onMeasure,onTouchEvent等事件,来实现想要的效果。最后图片的添加放到xml中,这需要在attrs中添加自定义属性。

3.代码
  • MyToggleBtn .java
package com.sanmiao.mytest.myview;

import android.content.Context;
import android.content.res.TypedArray;
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 com.sanmiao.mytest.R;

/**
 * @作者 : 丁建强
 * @创建时间:2016/8/9 0009 17:36
 * @类说明 :自定义切换按钮
 */

public class MyToggleBtn extends View implements View.OnClickListener {
    private Bitmap currBtnBitmap, currBackBitmap;
    private Bitmap toggle_bg_on;
    private Bitmap toggle_bg_off;
    private Bitmap toggle_btn_on;
    private Bitmap toggle_btn_off;
    private Paint paint;
    private float slide_left = 0;
    private boolean currState = false;//当前开关状态,true 为开

    public MyToggleBtn(Context context) {
        this(context, null);
    }

    public MyToggleBtn(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyToggleBtn(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //初始化自定义属性
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyToggleBtn);
        currState = ta.getBoolean(R.styleable.MyToggleBtn_isChecked, false);
        int backOnId = ta.getResourceId(R.styleable.MyToggleBtn_backImageOn, 0);
        int backOffId = ta.getResourceId(R.styleable.MyToggleBtn_backImageOff, 0);
        int slideOnId = ta.getResourceId(R.styleable.MyToggleBtn_slideImageOn, 0);
        int slideOffId = ta.getResourceId(R.styleable.MyToggleBtn_slideImageOff, 0);

        toggle_bg_on = BitmapFactory.decodeResource(getResources(), backOnId);
        toggle_btn_on = BitmapFactory.decodeResource(getResources(), slideOnId);
        if (backOffId == 0) {
            toggle_bg_off = toggle_bg_on;
        } else {
            toggle_bg_off = BitmapFactory.decodeResource(getResources(), backOffId);
        }
        if (slideOffId == 0) {
            toggle_btn_off = toggle_btn_on;
        } else {
            toggle_btn_off = BitmapFactory.decodeResource(getResources(), slideOffId);
        }
        ta.recycle();
        initView();
    }

    private void initView() {
        currBtnBitmap = toggle_btn_off;
        currBackBitmap = toggle_btn_off;
        paint = new Paint();
        paint.setAntiAlias(true);//设置抗锯齿
        setOnClickListener(this);
        flushState();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //设置当前view 大小
        setMeasuredDimension(toggle_bg_on.getWidth(), toggle_btn_on.getHeight());
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //背景图片
        canvas.drawBitmap(currBackBitmap, 0, getHeight() / 2 - toggle_bg_on.getHeight() / 2, paint);
        //滑动按钮图片
        canvas.drawBitmap(currBtnBitmap, slide_left, 0, paint);

    }

    @Override
    public void onClick(View v) {
        currState = !currState;
        if (!isDrag) {
            flushState();
        }

    }

    /**
     * 刷新当前状态
     */
    private void flushState() {
        if (currState) {//开
            slide_left = toggle_bg_on.getWidth() - toggle_btn_off.getWidth();
            currBackBitmap = toggle_bg_on;
            currBtnBitmap = toggle_btn_on;
        } else {//关
            slide_left = 0;
            currBackBitmap = toggle_bg_off;
            currBtnBitmap = toggle_btn_off;
        }
        invalidate();
    }

    private int firstX, lastX;
    boolean isDrag = false;//是否拖动

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int maxLeft = getWidth() - currBtnBitmap.getWidth();//左边界做大值
        super.onTouchEvent(event);
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                firstX = lastX = (int) event.getX();
                isDrag = false;
                break;
            case MotionEvent.ACTION_MOVE:
                if (Math.abs(event.getX() - firstX) > 5) {
                    isDrag = true;
                }
                //计算手指在屏幕上移动的距离
                int dis = (int) (event.getX() - firstX);
                //将本次的位置设置给 lastX
                lastX = (int) event.getX();
                //根据手指移动的距离,改变slide_left的值
                slide_left = slide_left + dis;
                if (slide_left > maxLeft / 2) {
                    currBackBitmap = toggle_bg_on;
                    currBtnBitmap = toggle_btn_on;
                } else {
                    currBackBitmap = toggle_bg_off;
                    currBtnBitmap = toggle_btn_off;
                }
                break;
            case MotionEvent.ACTION_UP:
                if (isDrag) {
                    if (slide_left > maxLeft / 2) {
                        currState = true;
                    } else {
                        currState = false;
                    }
                    flushState();
                }
                break;
        }
        flushView();
        return true;
    }

    /**
     * 刷新视图
     */
    private void flushView() {
        //对slide_left进行判断 0<= slide_left <= maxLeft
        int maxLeft = getWidth() - currBtnBitmap.getWidth();//左边界做大值
        slide_left = slide_left > 0 ? slide_left : 0;
        slide_left = slide_left < maxLeft ? slide_left : maxLeft;
        invalidate();
    }

    /**
     * 是否打开
     *
     * @return
     */
    public boolean isChecked() {
        return currState;
    }
}
  • attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyToggleBtn">
        <attr name="isChecked" format="boolean" />
        <attr name="backImageOff" format="reference" />
        <attr name="backImageOn" format="reference" />
        <attr name="slideImageOn" format="reference" />
        <attr name="slideImageOff" format="reference" />
    </declare-styleable>
</resources>
  • activity_test.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center">

    <com.sanmiao.mytest.myview.MyToggleBtn
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        app:backImageOff="@mipmap/img_toggle_bg_off"
        app:slideImageOn="@mipmap/img_toggle_btn_on"
        app:slideImageOff="@mipmap/img_toggle_btn_off"
        app:backImageOn="@mipmap/img_toggle_bg_on"
        app:isChecked="true" />

    <com.sanmiao.mytest.myview.MyToggleBtn
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        app:slideImageOn="@mipmap/slide_button"
        app:backImageOn="@mipmap/switch_background"
        app:isChecked="true" />

</LinearLayout>
4.运行效果

这里写图片描述

5.说明

若按钮只有2张图片(背景和滑动图片)只需要在xml中添加 slideImageOn 和backImageOn
这两个属性就可以了;若有4张需要添加backImageOff、slideImageOn、slideImageOff、backImageOn这4个属性

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值