《自定義控件:策略模式-讓垃圾清理控件實現(xiàn)難度降低》

本文按自己實現(xiàn)的思路整理成博客供參考和日后復(fù)習(xí),直接上效果

運行效果
  • 1、控件分析
  • 2、巧用策略模式
  • 3、優(yōu)化
  • 4、工程源碼

1.控件分析

1.1狀態(tài)分析

初始狀態(tài):它的背景是一個圓

清理狀態(tài):背景圓先縮小成一個小圓,并帶動幾個小圓繞圓環(huán)運行,并且這些小圓之間的距離先拉開后又縮進重貼,依次反復(fù)。

清理完成:小圓拉開,向圓環(huán)中心聚合,背景圓有小擴大到初始狀態(tài)(顏色根據(jù)清理程度顯示不同顏色)

增強效果:以背景圓圓心為中心,擴散出很多大小、半徑、顏色、運行距離不同的小圓,并最終消失。(隨機的,即每次清理完,擴散小圓個數(shù),大小、透明度等等都是隨機的)

1.2定義屬性

分析哪些屬性可變,定義成屬性,支持布局文件中配置。個人習(xí)慣于先實現(xiàn)效果,最后根據(jù)需求再從代碼中分離出自定義屬性。

1.3 onMeasure測量

這個步驟不需要也行,但為了控件效果,寬高太小肯定不好看,所以測量過程根據(jù)給定的寬高和控制要求最小的寬高進行比較,取大值。

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int minHW = DensityUtils.dp2px(mMinHeightAndWidth);
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        height = Math.min(width, height);
        height = height > minHW ? height : minHW;
        mRadius = height / 4;
        setMeasuredDimension(width, height);
    }

minHW 是控件要求的最小寬高。之后所有的狀態(tài)都在控件寬高內(nèi)繪制。

1.4 onDraw繪制

分析
根據(jù)效果圖中,整個過程中出現(xiàn)的幾何圖形都是圓形,所以整個過程中也只涉及到一個API:canvas.drawCircle(cx,cy,radius,paint);
drawCircle這個方法的四個參數(shù):圓心的坐標(biāo)x和y,半徑radius,畫筆paint決定顏色,透明度等。

圓要運動或顯示在不同位置,只要改變x,y
圓大小變化,由半徑radius決定;
圓的顏色透明度等由paint設(shè)置。

所以不論何種狀態(tài),圓的動畫的運行原理就改變x,y,或者半徑radius或顏色。畫出對應(yīng)的圓,原理比較簡單。既然每個階段都是畫圓,并根據(jù)一定的算法不斷地改變圓坐標(biāo)或半徑,根據(jù)新的參數(shù)繪制圓,讓其“動起來”,所以動畫的執(zhí)行算法和每個狀態(tài)過度之間的動畫才是我們需要深入考慮的。

按上述的分析,定義方法 drawBackground(Canvas canvas) 用于畫背景圓
定義方法drawBoll(Canvas canvas)用于畫繞圓環(huán)運動的圓等等,讓后在onDraw(Canvas canvas)中根據(jù)條件調(diào)用不同的畫方法,每個draw方法對應(yīng)一個valueAnimator,執(zhí)行具體的運動算法(詳細看代碼),不同的狀態(tài)下執(zhí)行不同的valueAnimator。哇,這樣看來顯得過于復(fù)雜。

每一種狀態(tài),都是一種畫方法(draw)對應(yīng)一種運動算法(valueAnimator)。所以可以抽取為一種“狀態(tài)”如下


public abstract class ClearViewAnim {
    /**
     * 執(zhí)行繪畫
     *
     * @param canvas 畫布
     */
    public abstract void drawState(Canvas canvas);

    /**
     * 執(zhí)行動畫
     */
    public abstract void startAnim();

    /**
     * 停止動畫
     */
    public abstract void stopAnim();
}

讓各種狀態(tài)都繼承ClearViewAnim ,讓后各自實現(xiàn)自己的畫方法和運動動畫。


圖片.png

//定義初始狀態(tài)
class InitAnim extends ClearViewAnim{
        public InitAnim(int status) {
            currentState = status;
            //初始化valueAnimator 定義具體的運動算法
        }

        @Override
        public void drawState(Canvas canvas) {
            //調(diào)用具體的繪制方法
            drawBackground(canvas);
        }

        @Override
        public void startAnim() {
            valueAnimator.start();
        }

        @Override
        public void stopAnim() {
            valueAnimator.cancel();
        }
    }

//清理狀態(tài)
 class RunningAinm extends ClearViewAnim {
  //省略...
}

//清理完成狀態(tài)
class FinishAinm extends ClearViewAnim {
 //省略...
}
//增強效果狀態(tài)
class ExpendAmin extends ClearViewAnim {
//省略...
}

這個時候onDraw方法就變成這樣,代碼非常簡潔。

    //動畫狀態(tài)抽象類
    private ClearViewAnim mViewAnim;

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mViewAnim == null) {
            //初始狀態(tài)InitAnim
            mViewAnim = new InitAnim(STATE_INIT);
        }
        mViewAnim.drawState(canvas);
    }

由于mViewAnim 是抽象類, mViewAnim.drawState(canvas)具體執(zhí)行什么狀態(tài)下的畫方法,由其子類決定的,所以根據(jù)不同的時機將mViewAnim替換成InitAnim、RunningAinm 、FinishAinm 、ExpendAmin 就執(zhí)行對應(yīng)狀態(tài)下的畫方法和運動算法。

2.巧用策略模式

上述動畫狀態(tài)的抽取,替換,使用了正是策略模式。

定義:策略模式是指對一系列的算法定義,并將每一個算法封裝起來,而且使它們還可以相互替換。策略模式讓算法獨立于使用它的客戶而獨立變化。

使用了策略模式后,現(xiàn)在再加一個動畫狀態(tài)此時顯得非常簡單,比如在FinishAnim狀態(tài)之后,還想執(zhí)行一個Clear狀態(tài)的動畫,那么定義一個ClearAnim繼承于ClearViewAnim。
mViewAnim = new FinishAnim();替換成mViewAnim = new ClearAnim();

圖片.png

無論擴展多種狀態(tài),只需要新建一個狀態(tài)Anim繼承于狀態(tài)抽象類,而無需對onDraw進行改動,這滿足了程序設(shè)計的一條重要原則"對修改關(guān)閉、對擴展開放"

3.優(yōu)化

4.工程源碼

本文沒有對具體的運行動畫展開,主要都是一些數(shù)學(xué)計算,工程已托管在github上,歡迎start!
工程源碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容