自定義view————開關button

陷入自定義view的坑越陷越深,勵志要把自定義view擼給遍,今天給你們介紹一下自定義view————開關button,這個在不少app中都能用的,廢話很少說,先來給動圖。android

效果圖
效果圖

分析一下上面的效果:四個狀態:關閉狀態、關閉->打開過程、打開狀態、打開->關閉過程,結合ValueAnimator動效實現這個過程git

關閉狀態

繪製一個圓角矩形(drawRoundRect()方法),再畫一個圓(drawCircle()),默認關閉就畫好了github

RectF rectF = new RectF(padding, padding, mwidth - padding, mheight - padding);
    //先畫背景
    canvas.drawRoundRect(rectF, backgroundRadius, backgroundRadius, closePaint);

    //再畫圓
    canvas.drawCircle(closecenterX, closecenterY, circleRadius, circlePaint);複製代碼

打開狀態

繪製了關閉狀態,再繪製打開狀態,,最後繪製關閉->打開狀態,打開->關閉狀態,其實這裏和關閉狀態相似的,只是畫圓的x、y的位置不同而已canvas

RectF rectF = new RectF(padding, padding, mwidth - padding, mheight - padding);
    //先畫背景
    canvas.drawRoundRect(rectF, backgroundRadius, backgroundRadius, closePaint);

    RectF rectFAnimation = new RectF(padding, padding, o2cright, o2cbottom);
    //先畫背景
    canvas.drawRoundRect(rectFAnimation, backgroundRadius, backgroundRadius, openPaint);

    //再畫圓
    canvas.drawCircle(o2ccenterX, o2ccenterY, circleRadius, circlePaint);複製代碼

關閉->打開狀態

ValueAnimator動效中的addUpdateListener()的回調經過valueAnimator.getAnimatedValue();來從新繪製過程,計算圓在狀態變化時的x,y及其圓角矩形的right,bottom值來動態改變而後從新繪製。bash

記錄動態的變化值 服務器

close2OpengvalueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator valueAnimator) {
                 mclose2OpenAnimatorValue = (float) valueAnimator.getAnimatedValue();
                 //圓在狀態變化時的x,y
                 c2ocenterX = closecenterX + closeOpenX * mclose2OpenAnimatorValue;
                 c2ocenterY = backgroundRadius + padding;
                 //背景的右下標=關閉狀態的位置(2*backgroundRadius+padding)+差值*變化
                 c2oright = 2 * backgroundRadius + padding + closeOpenRight * mclose2OpenAnimatorValue;
                 //背景的底下標=關閉狀態的位置(2*backgroundRadius+padding)+差值*變化
                 c2obottom = 2 * backgroundRadius + padding + closeOpenBottom * mclose2OpenAnimatorValue;
                 invalidate();
             }
         });
         close2OpengvalueAnimator.addListener(new Animator.AnimatorListener() {
             @Override
             public void onAnimationStart(Animator animator) {

             }

             @Override
             public void onAnimationEnd(Animator animator) {
                 setOpen();
                 invalidate();
             }

             @Override
             public void onAnimationCancel(Animator animator) {

             }

             @Override
             public void onAnimationRepeat(Animator animator) {

             }
         });複製代碼

根據變化值從新繪製app

RectF rectF = new RectF(padding, padding, mwidth - padding, mheight - padding);
     //先畫背景
     canvas.drawRoundRect(rectF, backgroundRadius, backgroundRadius, closePaint);

     RectF rectFAnimation = new RectF(padding, padding, c2oright, c2obottom);
     //先畫背景
     canvas.drawRoundRect(rectFAnimation, backgroundRadius, backgroundRadius, openPaint);

     //再畫圓
     canvas.drawCircle(c2ocenterX, c2ocenterY, circleRadius, circlePaint);複製代碼

打開->關閉狀態

這個動畫狀態和上面的動畫狀態同理ide

記錄變化值動畫

openg2ClosevalueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                mopeng2CloseAnimatorValue = (float) valueAnimator.getAnimatedValue();

                //圓在狀態變化時的x,y
                o2ccenterX = closecenterX+closeOpenX * mopeng2CloseAnimatorValue;
                o2ccenterY = backgroundRadius + padding;
                //背景的右下標=關閉狀態的位置(2*backgroundRadius+padding)+差值*變化
                o2cright = 2 * backgroundRadius + padding + closeOpenRight * mopeng2CloseAnimatorValue;
                //背景的底下標=關閉狀態的位置(2*backgroundRadius+padding)+差值*變化
                o2cbottom = 2 * backgroundRadius + padding + closeOpenBottom * mopeng2CloseAnimatorValue;
                invalidate();

            }
        });
        openg2ClosevalueAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {

            }

            @Override
            public void onAnimationEnd(Animator animator) {
                setClose();
                invalidate();
            }

            @Override
            public void onAnimationCancel(Animator animator) {

            }

            @Override
            public void onAnimationRepeat(Animator animator) {

            }
        });複製代碼

根據變化值從新繪製ui

RectF rectF = new RectF(padding, padding, mwidth - padding, mheight - padding);
            //先畫背景
            canvas.drawRoundRect(rectF, backgroundRadius, backgroundRadius, closePaint);

            RectF rectFAnimation = new RectF(padding, padding, o2cright, o2cbottom);
            //先畫背景
            canvas.drawRoundRect(rectFAnimation, backgroundRadius, backgroundRadius, openPaint);

            //再畫圓
            canvas.drawCircle(o2ccenterX, o2ccenterY, circleRadius, circlePaint);複製代碼

上面的四種狀態介紹完畢了,大體功能就實現了,接下來介紹一些屬性的設置、四種狀態設置的方法、點擊事件等

四種狀態的設置

/***
     * 關閉
     */
    private void setClose() {
        mcurrentState = State.CLOSE;
        invalidate();
    }

    /***
     * 打開
     */
    private void setOpen() {
        mcurrentState = State.OPEN;
        invalidate();
    }

    /***
     * 關閉到打開
     */
    private void setClose2Open() {
        mcurrentState = State.CLOSE2OPEN;
        openg2ClosevalueAnimator.removeAllUpdateListeners();
        addCloseToOpenAnimator();
        close2OpengvalueAnimator.start();
    }

    /***
     * 打開到關閉
     */
    private void setOpen2Close() {
        mcurrentState = State.OPEN2CLOSE;
        close2OpengvalueAnimator.removeAllUpdateListeners();
        addOpenToCloseAnimator();
        openg2ClosevalueAnimator.start();
    }複製代碼

點擊事件執行打開關閉

/***
     * 控件點擊執行該方法 改變狀態
     */
    public void onclick(){
        if(mcurrentState==State.CLOSE){
            setClose2Open();
        }else if(mcurrentState==State.OPEN){
            setOpen2Close();
        }
    }複製代碼

屬性的設置

xml設置

attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="SwitchButton">
        <attr name="backgroudColor" format="color"/>
        <attr name="closeColor" format="color"/>
        <attr name="openColor" format="color"/>
        <attr name="circleColor" format="color"/>
        <attr name="animatorTime" format="integer"/>
        <attr name="padding" format="integer"/>
    </declare-styleable>
</resources>複製代碼
private void initTypeArray(Context context, AttributeSet attrs) {
        TypedArray typedArray=context.obtainStyledAttributes(attrs,R.styleable.SwitchButton);
        backgroudColor=typedArray.getColor(R.styleable.SwitchButton_backgroudColor,Color.WHITE);
        closeColor=typedArray.getColor(R.styleable.SwitchButton_closeColor,Color.GRAY);
        openColor=typedArray.getColor(R.styleable.SwitchButton_openColor,Color.GREEN);
        circleColor=typedArray.getColor(R.styleable.SwitchButton_circleColor,Color.WHITE);
        padding=typedArray.getInteger(R.styleable.SwitchButton_padding,1);
        animatorTime=typedArray.getInteger(R.styleable.SwitchButton_animatorTime,500);
        typedArray.recycle();
    }複製代碼

xml中設置

<com.switchbutton.SwitchButton
        android:id="@+id/btn1"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:layout_marginTop="20dp"
        app:closeColor="@color/colorAccent"
        app:openColor="@android:color/holo_green_light"
        app:padding="6"
        app:animatorTime="1000"
        />複製代碼

代碼設置

/**
     * 設置背景顏色
     * @param backgroudColor
     */
    public void setBackgroudColor(int backgroudColor) {
        this.backgroudColor = backgroudColor;
    }

    /**
     * 關閉狀態顏色
     * @param closeColor
     */
    public void setCloseColor(int closeColor) {
        this.closeColor = closeColor;
        closePaint.setColor(closeColor);
    }

    /**
     * 打開狀態顏色
     * @param openColor
     */
    public void setOpenColor(int openColor) {
        this.openColor = openColor;
        openPaint.setColor(openColor);
    }

    /**
     * 圓的顏色
     * @param circleColor
     */
    public void setCircleColor(int circleColor) {
        this.circleColor = circleColor;
        circlePaint.setColor(circleColor);
    }

    /**
     * 間距
     * @param padding
     */
    public void setPadding(int padding) {
        this.padding = padding;
    }

    /**
     * 動畫時間
     * @param animatorTime
     */
    public void setAnimatorTime(int animatorTime) {
        this.animatorTime = animatorTime;
    }複製代碼

考慮實踐應用中,須要獲取相關狀態,上傳至服務器/根據狀態設置相關設置等

/**
     * 獲取當前的狀態 用於使用時的需求
     * @return
     */
    public State getMcurrentState() {
        return mcurrentState;
    }複製代碼

其餘方法也能夠實現,根據本身的需求去作相應的更改

SwitchButton GitHub demo地址

我的博客

相關文章
相關標籤/搜索