自定義SwitchButton

先來看效果
先來看效果

android界面繪製流程 measure->layout->draw
也就是 測量->擺放->繪製

public class SwitchView extends View {

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //這裏測量畫view的大小
        setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
    }

    public SwitchView(Context context) {
        super(context);
    }
    //如果在xml文件中定義了資源 就會走到這個方法裏 需要我們手動的將資源加載進來
    public SwitchView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    //如果設置了樣式 style 則走此方法
    public SwitchView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //在這裏面 畫button
    }

直接上帶碼

public class SwitchView extends View {
    //畫筆
    private Paint paint;
    private Bitmap mButton;
    private Bitmap mSwitchBackground;
    private Bitmap mSliderBackground;
    private Bitmap mMask;
    private PorterDuffXfermode mfermode;
    //開關狀態
    private boolean mState;
    private float mCurrentX;

    private OnStateChangeListener mOnStateChangeListener;

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

    public SwitchView(Context context) {
        super(context);
        init();
    }

    public SwitchView(Context context, AttributeSet attrs) {
        super(context, attrs);
        //命名空間
        String namespace = "http://schemas.android.com/apk/res-auto";
        //默認的開關狀態
        boolean state = attrs.getAttributeBooleanValue(namespace, "state", true);
        //滑動背景
        int slider_background = attrs.getAttributeResourceValue(namespace, "slider_background", -1);
        //開關背景
        int switch_background = attrs.getAttributeResourceValue(namespace, "switch_background", -1);
        //按鈕
        int button = attrs.getAttributeResourceValue(namespace, "button", -1);
        //遮罩
        int mask = attrs.getAttributeResourceValue(namespace, "mask", -1);


        setSwitchBackground(switch_background);
        setSliderBackground(slider_background);
        setButton(button);
        setMask(mask);
        init();
    }

    public SwitchView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {

        //初始化畫筆
        paint = new Paint();
        //初始化圖像合成類
        mfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
    }

    @Override
    protected void onDraw(Canvas canvas) {

        int saveFlags = Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG | Canvas
                .HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG | Canvas
                .CLIP_TO_LAYER_SAVE_FLAG;
        canvas.saveLayer(0, 0, mSwitchBackground.getWidth(), mSwitchBackground.getHeight(), null,
                saveFlags);
        canvas.drawBitmap(mMask, 0, 0, paint);
        paint.setXfermode(mfermode);



        //定義滑塊可到達的最大值 最小值
        float btnMaxLeft = - mButton.getWidth() / 2.0f + (mButton.getHeight()-15)/2.0f;
        float btnMaxRight = 0;
        float sliderMaxLeft = - mSliderBackground.getWidth() / 2.0f + (mButton.getHeight()-15)/2.0f;
        float sliderMaxRight = 0;

        if(isSlideMode){
            //在滑動狀態下面 計算當前位置
            float btnNewLeft = mCurrentX - mButton.getWidth() / 2.0f;
            float sliderNewLeft = mCurrentX - mSliderBackground.getWidth() / 2.0f;
            // 限定滑塊範圍
            if(btnNewLeft <  btnMaxLeft){
                btnNewLeft =  btnMaxLeft; // 左邊範圍
            }else if (btnNewLeft > btnMaxRight) {
                btnNewLeft = btnMaxRight; // 右邊範圍
            }
            if(sliderNewLeft <  sliderMaxLeft){
                sliderNewLeft =  sliderMaxLeft; // 左邊範圍
            }else if (sliderNewLeft > sliderMaxRight) {
                sliderNewLeft = sliderMaxRight; // 右邊範圍
            }


            canvas.drawBitmap(mSliderBackground, sliderNewLeft, 0, paint);
            paint.setXfermode(null);
            canvas.drawBitmap(mSwitchBackground,0,0,paint);
            //最後畫開關
            canvas.drawBitmap(mButton, btnNewLeft, 0, paint);
        }else {
            if(mState){
                canvas.drawBitmap(mSliderBackground, sliderMaxLeft, 0, paint);
                paint.setXfermode(null);
                canvas.drawBitmap(mSwitchBackground,0,0,paint);
                canvas.drawBitmap(mButton, btnMaxLeft, 0, paint);
            }else {
                canvas.drawBitmap(mSliderBackground, sliderMaxRight, 0, paint);
                paint.setXfermode(null);
                canvas.drawBitmap(mSwitchBackground,0,0,paint);
                canvas.drawBitmap(mButton, btnMaxRight, 0, paint);
            }
        }

        canvas.restore();

    }

    private boolean isSlideMode = false;
    private float upX ;
    private float startX ;
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN:

                mCurrentX = event.getX();
                startX = mCurrentX;

                break;
            case MotionEvent.ACTION_MOVE:
                if(Math.abs(startX-event.getX())>2){


                isSlideMode = true;
                mCurrentX = event.getX(); }
                break;

            case MotionEvent.ACTION_UP:
                isSlideMode = false;
                float upX = event.getX();
                if(upX == startX){
                    mState = !mState;
                    mOnStateChangeListener.onStateChange(mState);
                    break;
                }
                float center = mSwitchBackground.getWidth() / 2.0f;
                boolean oldState = mState;
                mState = center > mCurrentX;
                if(oldState != mState){
                    mOnStateChangeListener.onStateChange(mState);
                }

                break;
        }
        //重繪界面
        invalidate();
        //消費掉該事件 纔可以接收其它事件
        return true;
    }

    /**
     * 設置switch背景
     * @param id
     */
    public void setSwitchBackground(int id) {
        mSwitchBackground = BitmapFactory.decodeResource(getResources(), id);
    }

    /**
     * 設置滑動條背景
     * @param id
     */
    public void setSliderBackground(int id) {
        mSliderBackground = BitmapFactory.decodeResource(getResources(), id);
    }

    /**
     * 設置按鈕
     * @param id
     */
    public void setButton(int id) {
        mButton = BitmapFactory.decodeResource(getResources(), id);
    }

    /**
     * 設置遮罩
     * @param id
     */
    public void setMask(int id) {
        mMask = BitmapFactory.decodeResource(getResources(), id);
    }
    //定義回調接口
    public interface OnStateChangeListener{
        void onStateChange(boolean state);
    }
    //暴露接口一個可以設置監聽
    public void setOnStateChangeListener(OnStateChangeListener onStateChangeListener){
        this.mOnStateChangeListener = onStateChangeListener;
    }

}

別忘了根佈局定義命名空間
xmlns:reige=”http://schemas.android.com/apk/res-auto”

<com.example.reige.switchview.view.SwitchView
        android:id="@+id/switch_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        reige:button="@mipmap/switch_button"
        reige:slider_background="@mipmap/slider_background"
        reige:switch_background="@mipmap/switch_background"
        reige:mask="@mipmap/bitmap_mask"
        />

源碼地址 ->> github
圖像合成相關 http://www.tuicool.com/articles/6RjE3m

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章