1.自定义属性values/attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="ToggleView">
        <attr name="switch_background" format="reference" />
        <attr name="slide_button" format="reference" />
        <attr name="switch_state" format="boolean" />
    </declare-styleable>

</resources>

2.view的java文件:

package zdl.switchbutton.view;

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;

/**
 * 自定义开关
 *
 */
public class ToggleView extends View {

    private Bitmap switchBackgroupBitmap; // 背景图片
    private Bitmap slideButtonBitmap; // 滑块图片
    private Paint paint; // 画笔
    private boolean mSwitchState = false; // 开关状态, 默认false
    private float currentX;

    /**
     * 用于代码创建控件
     *
     * @param context
     */
    public ToggleView(Context context) {
        super(context);
        init();
    }

    /**
     * 用于在xml里使用, 可指定自定义属性
     *
     * @param context
     * @param attrs
     */
    public ToggleView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
        // 获取配置的自定义属性
        String namespace = "http://toly.android.com/apk/res/zdl.switchbutton.view.ToggleView";
        int switchBackgroundResource = attrs.getAttributeResourceValue(namespace, "switch_background", -1);
        int slideButtonResource = attrs.getAttributeResourceValue(namespace, "slide_button", -1);

        mSwitchState = attrs.getAttributeBooleanValue(namespace, "switch_state", false);
        setSwitchBackgroundResource(switchBackgroundResource);
        setSlideButtonResource(slideButtonResource);
    }

    /**
     * 用于在xml里使用, 可指定自定义属性, 如果指定了样式, 则走此构造函数
     *F:\Android\SwitchButton\app\src\main\java\zdl\switchbutton\view\ToggleView.java
     * zdl.switchbutton.view.ToggleView
     * @param context
     * @param attrs
     * @param defStyle
     */
    public ToggleView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        paint = new Paint();
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(switchBackgroupBitmap.getWidth(), switchBackgroupBitmap.getHeight());
    }

    // Canvas 画布, 画板. 在上边绘制的内容都会显示到界面上.
    @Override
    protected void onDraw(Canvas canvas) {
        // 1. 绘制背景
        canvas.drawBitmap(switchBackgroupBitmap, 0, 0, paint);

        // 2. 绘制滑块

        if (isTouchMode) {
            // 根据当前用户触摸到的位置画滑块

            // 让滑块向左移动自身一半大小的位置
            float newLeft = currentX - slideButtonBitmap.getWidth() / 2.0f;

            int maxLeft = switchBackgroupBitmap.getWidth() - slideButtonBitmap.getWidth();

            // 限定滑块范围
            if (newLeft < 0) {
                newLeft = 0; // 左边范围
            } else if (newLeft > maxLeft) {
                newLeft = maxLeft; // 右边范围
            }

            canvas.drawBitmap(slideButtonBitmap, newLeft, 0, paint);
        } else {
            // 根据开关状态boolean, 直接设置图片位置
            if (mSwitchState) {// 开
                int newLeft = switchBackgroupBitmap.getWidth() - slideButtonBitmap.getWidth();
                canvas.drawBitmap(slideButtonBitmap, newLeft, 0, paint);
            } else {// 关
                canvas.drawBitmap(slideButtonBitmap, 0, 0, paint);
            }
        }

    }

    boolean isTouchMode = false;
    private OnSwitchListener onSwitchListener;

    // 重写触摸事件, 响应用户的触摸.
    @Override
    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                isTouchMode = true;
                System.out.println("event: ACTION_DOWN: " + event.getX());
                currentX = event.getX();
                break;
            case MotionEvent.ACTION_MOVE:
                System.out.println("event: ACTION_MOVE: " + event.getX());
                currentX = event.getX();
                break;
            case MotionEvent.ACTION_UP:
                isTouchMode = false;
                System.out.println("event: ACTION_UP: " + event.getX());
                currentX = event.getX();

                float center = switchBackgroupBitmap.getWidth() / 2.0f;

                // 根据当前按下的位置, 和控件中心的位置进行比较.
                boolean state = currentX > center;

                // 如果开关状态变化了, 通知界面. 里边开关状态更新了.
                if (state != mSwitchState && onSwitchListener != null) {
                    // 把最新的boolean, 状态传出去了
                    onSwitchListener.onStateUpdate(state);
                }

                mSwitchState = state;
                break;

            default:
                break;
        }

        // 重绘界面
        invalidate(); // 会引发onDraw()被调用, 里边的变量会重新生效.界面会更新

        return true; // 消费了用户的触摸事件, 才可以收到其他的事件.
    }

    /**
     * 设置背景图
     *
     * @param switchBackground
     */
    public void setSwitchBackgroundResource(int switchBackground) {
        switchBackgroupBitmap = BitmapFactory.decodeResource(getResources(), switchBackground);
    }

    /**
     * 设置滑块图片资源
     *
     * @param slideButton
     */
    public void setSlideButtonResource(int slideButton) {
        slideButtonBitmap = BitmapFactory.decodeResource(getResources(), slideButton);
    }

    /**
     * 设置开关状态
     */
    public void setSwitchState(boolean mSwitchState) {
        this.mSwitchState = mSwitchState;
    }

    public interface OnSwitchListener {
        // 状态回调, 把当前状态传出去
        void onStateUpdate(boolean state);
    }

    public void setOnSwitchListener(OnSwitchListener onSwitchListener) {
        this.onSwitchListener = onSwitchListener;
    }

}


3.layout中使用

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:toly="http://toly.android.com/apk/res/zdl.switchbutton.view.ToggleView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

<zdl.switchbutton.view.ToggleView
    android:id="@+id/toggleView"
    toly:switch_background="@drawable/switch_background"
    toly:slide_button="@drawable/slide_button"
    toly:switch_state="false"
    android:layout_width="20dp"
    android:layout_height="wrap_content"/>
</LinearLayout>

4.MainActivity.java中:

package zdl.switchbutton;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

import zdl.switchbutton.view.ToggleView;

public class MainActivity extends AppCompatActivity {

    private Toolbar mTb;
    private ToggleView toggleView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        toggleView = (ToggleView) findViewById(R.id.toggleView);
        // 设置开关更新监听
        toggleView.setOnSwitchListener(new ToggleView.OnSwitchListener(){

            @Override
            public void onStateUpdate(boolean state) {
                Toast.makeText(getApplicationContext(), "state: " + state, 0).show();
            }

        });


}


posted on 2017-12-22 22:54  张风捷特烈  阅读(147)  评论(0编辑  收藏  举报