Android-自定義開關(升級版)

效果圖:java

 

 

定義一個類,取名爲MySwitch.java,此類去繼承View,爲什麼是繼承View而不是去繼承ViewGroup呢,是由於自定義開關沒有子控件,之須要操做自身繪製便可android

package custom.view.upgrade.my_switch;

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.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import custom.view.R;

public class MySwitch extends View implements View.OnClickListener {

    private static String TAG = MySwitch.class.getSimpleName();

    private Paint mPaint;

    /**
     * 讓佈局中來指定實例化,獲得屬性集合AttributeSet
     * @param context
     * @param attrs
     */
    public MySwitch(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        initView(context, attrs);
        initListener();
    }

    // 定義按鈕背景圖片
    private Bitmap bmSwitchBackground;

    // 定義按鈕拖動的圖片
    private Bitmap bmSwitchDrag;

    // 定義開關的狀態 true || false , 默認是關閉狀態
    private boolean switchStatus;

    // 定義開關的臨時記錄狀態
    private boolean tempSwitchStatus;

    // 定義按鈕拖動距離左邊的距離
    private int dragLife = -1;

    /**
     * 初始化工做
     */
    private void initView(Context context, AttributeSet attrs) {
        mPaint = new Paint();
        mPaint.setAntiAlias(true); // 抗鋸齒

        // 獲取屬性
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MySwitch);
        bmSwitchBackground = ((BitmapDrawable) typedArray.getDrawable(R.styleable.MySwitch_switch_background)).getBitmap();
        bmSwitchDrag = ((BitmapDrawable) typedArray.getDrawable(R.styleable.MySwitch_switch_drag)).getBitmap();
        switchStatus = typedArray.getBoolean(R.styleable.MySwitch_switch_status, false);
    }

    public void setBmSwitchBackground(int switchBackground) {
        this.bmSwitchBackground = BitmapFactory.decodeResource(getResources() ,switchBackground);
    }

    public void setBmSwitchDrag(int switchDrag) {
        this.bmSwitchDrag = BitmapFactory.decodeResource(getResources(), switchDrag);
    }

    public void setSwitChStatus(boolean switchStatus) {
        this.switchStatus = switchStatus;
        dragLife = -1;
    }

    /**
     * 初始化事件
     */
    private void initListener() {
        setOnClickListener(this);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        // 寬度是:按鈕背景的寬度
        // 高度是:按鈕背景的高度
        // 測量自身View
        setMeasuredDimension(bmSwitchBackground.getWidth(), bmSwitchBackground.getHeight());
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // 繪製按鈕背景
        canvas.drawBitmap(bmSwitchBackground, 0, 0, mPaint);

        if (dragLife != -1) {
            canvas.drawBitmap(bmSwitchDrag, dragLife, 0 , mPaint);
        } else if (dragLife == -1) {
            if (switchStatus) {
                // 打開狀態
                // 滑動點向右就是開啓狀態
                int openDragLife = getLifeDragMaxValue();
                canvas.drawBitmap(bmSwitchDrag, openDragLife, 0, mPaint);
                moveEndX = openDragLife;
            } else {
                // 關閉狀態
                canvas.drawBitmap(bmSwitchDrag, 0, 0, mPaint);
                moveEndX = 0;
            }

            // 當開關的狀態發生變化後,回調方法告訴用戶,開關改變了
            if (null != onSwitchChangeListener && switchStatusChange) {
                if (tempSwitchStatus != switchStatus) {
                    onSwitchChangeListener.onSwitchChange(switchStatus);
                }
            }
        }
    }

    private float downX;
    private int moveEndX;

    private float clickDown;
    private float clickMove;

    // 開關狀態是否發送了改變
    private boolean switchStatusChange;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event); // 必需要調用此方法,onClick點擊事件方法纔會生效
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downX = event.getX();
                isClick = true;
                clickDown = event.getX();
                switchStatusChange = false;
                tempSwitchStatus = switchStatus;
                break;
            case MotionEvent.ACTION_MOVE:
                // Log.d(TAG, ">>>>>不加等於:" + (int) (event.getX() - downX));
                moveEndX += (int) (event.getX() - downX);
                Log.d(TAG,">>>>>>加等於:" + moveEndX);

                if (moveEndX > getLifeDragMaxValue()) {
                    moveEndX = getLifeDragMaxValue();
                } else if (moveEndX < 0){
                    moveEndX = 0;
                }

                dragLife = moveEndX;
                invalidate();

                downX = event.getX();

                clickMove = downX;
                if (Math.abs(clickMove - clickDown) > 5) {
                    isClick = false;
                }

                break;
            case MotionEvent.ACTION_UP:
                if (dragLife > (getLifeDragMaxValue() / 2)) {
                    dragLife = -1;
                    switchStatus = true;
                    switchStatusChange = true;
                } else if (dragLife >= 0){
                    dragLife  = -1;
                    switchStatus = false;
                    switchStatusChange = true;
                } else {
                    switchStatusChange = false;
                }
                invalidate();
                // upX = (int) event.getX();
                break;
            default:
                break;
        }
        return true;
    }

    private int getLifeDragMaxValue() {
        return bmSwitchBackground.getWidth() - bmSwitchDrag.getWidth();
    }

    /*@Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        if (switchStatus) {
            moveEndX = getLifeDragMaxValue();
            Log.d(TAG, ">>>>>>>>>>>>>>>>>onFinishInflate()............ getLifeDragMaxValue():" + getLifeDragMaxValue());
        }
    }*/

    /**
     * 定義點擊事件狀態
     */
    private boolean isClick = true;

    @Override
    public void onClick(View v) {
        Log.d(TAG, "onClick() isClick:" + isClick);
        if (isClick) {
            if (switchStatus) {
                switchStatus = false;
                switchStatusChange = true;
            } else {
                switchStatus = true;
                switchStatusChange = true;
            }
            // switchStatus = (switchStatus==true?false:true);
            dragLife = -1;
            invalidate();
        }
    }

    private OnSwitchChangeListener onSwitchChangeListener;

    /**
     * 用戶設置的 狀態監聽
     * @param onSwitchChangeListener
     */
    public void setOnSwitchChangeListener(OnSwitchChangeListener onSwitchChangeListener) {
        this.onSwitchChangeListener = onSwitchChangeListener;
    }
}

 

佈局文件中去引用寫好的自定義開關類canvas

並設置自定義屬性:ide

     myswitch:switch_background="@mipmap/switch_background"
        myswitch:switch_drag="@mipmap/switch_drag"
        myswitch:switch_status="true"
<!-- 自定義開關升級版 -->
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:myswitch="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".upgrade.MainActivity">

    <!-- 使用wrap_content,是由於不知道按鈕的背景有多大,更加按鈕圖片的改變而變化 -->
    <custom.view.upgrade.my_switch.MySwitch
        android:id="@+id/custom_myswitch"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        myswitch:switch_background="@mipmap/switch_background"
        myswitch:switch_drag="@mipmap/switch_drag"
        myswitch:switch_status="true"
        />

</RelativeLayout>

 

自定義規則arrts.xml文件聲明:佈局

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

    <declare-styleable name="MySwitch">

        <attr name="switch_status" format="boolean" />

        <attr name="switch_background" format="reference" />

        <attr name="switch_drag" format="reference" />

    </declare-styleable>

</resources>

 

模擬用戶來使用:this

MySwitch mySwitch = findViewById(R.id.custom_myswitch);

        // 設置開關的背景圖片
        mySwitch.setBmSwitchBackground(R.mipmap.switch_background);

        // 設置開關拖動的圖片
        mySwitch.setBmSwitchDrag(R.mipmap.switch_drag);

        // 設置開關的狀態,打開、關閉
        mySwitch.setSwitChStatus(false);

        mySwitch.setOnSwitchChangeListener(new OnSwitchChangeListener() {
            @Override
            public void onSwitchChange(boolean switchChangeStatus) {
                String result;
                if (switchChangeStatus) {
                    result = "打開";
                } else {
                    result = "關閉";
                }
                Toast.makeText(MainActivity.this, "開關已" + result, Toast.LENGTH_SHORT).show();
            }
        });
相關文章
相關標籤/搜索