打造兼容的Android揭面水波動畫庫

今天看到了@Anderson大碼渣寫的文章繁扎,對5.0以上默認使用ViewAnimationUtils.createCircularReveal(view, centerX, centerY, startRadius, endRadius);來實現(xiàn)漸變怒炸,

預覽
,寫得非常好,這一塊的封裝就跳過了俯邓,可以直接看他的原文甩恼。

4.0以上兼容

要想在低版本中也能正常使用贡羔,我們可以直接自定義一個viewGroup云稚,掛載在decorview上,然后使用canvas.clipPath裁剪一個圓进统,這樣達到覆蓋的目的助币。


public class CircularRevealLayout extends FrameLayout {

    private static final String TAG = "CircularRevealLayout";

    private float revealRadius;
    private int centerX;
    private int centerY;
    private float startRadius;
    private float endRadius;

    private View childRevealView;
    private boolean isRunning = false;//動畫是否正在執(zhí)行
    private Path path;//繪制路徑



    public CircularRevealLayout(Context context) {
        this(context, null, 0);
    }

    public CircularRevealLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

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

    }

    private void init() {
        path = new Path();
        setFocusable(false);
    }

    /**
     * 設置要揭示的子view
     * @param childRevealView
     */
    public void setChildRevealView(View childRevealView) {
        this.childRevealView = childRevealView;
    }

    /**
     * 設置要揭示的子view的下標
     * @param index
     */
    public void setChildRevealViewIndex(int index) {
        if(getChildCount()>index){
            this.childRevealView=getChildAt(index);
        }

    }

    /**
     * 設置揭示半徑
     * @param revealRadius
     */
    private void setRevealRadius(float revealRadius) {
        this.revealRadius = revealRadius;
        Log.e(TAG, "revealRadius=" + revealRadius);
        invalidate();
    }

    /**
     * 設置揭示的中心點x坐標
     * @param centerX
     */
    public void setCenterX(int centerX) {
        this.centerX = centerX;
    }

    /**
     * 設置揭示的中心點y坐標
     * @param centerY
     */

    public void setCenterY(int centerY) {
        this.centerY = centerY;
    }

    /**
     * 設置揭示的開始半徑
     * @param startRadius
     */
    public void setStartRadius(float startRadius) {
        this.startRadius = startRadius;

    }

    /**
     * 設置揭示的結束半徑
     * @param endRadius
     */
    public void setEndRadius(float endRadius) {
        this.endRadius = endRadius;
    }


    public Animator getAnimator() {

        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(this, "revealRadius", startRadius, endRadius);
        objectAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {
                isRunning = true;
            }

            @Override
            public void onAnimationEnd(Animator animator) {
                isRunning = false;
            }

            @Override
            public void onAnimationCancel(Animator animator) {
                isRunning = false;
            }

            @Override
            public void onAnimationRepeat(Animator animator) {

            }
        });
        return objectAnimator;
    }

    @Override
    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
        if (isRunning && child == childRevealView) {
            final int state = canvas.save();

            path.reset();
            path.addCircle(centerX, centerY, revealRadius, Path.Direction.CW);//Pat.Direction.CW:順時針

            canvas.clipPath(path);//裁剪

            boolean isInvalided = super.drawChild(canvas, child, drawingTime);

            canvas.restoreToCount(state);

            return isInvalided;
        }

        return super.drawChild(canvas, child, drawingTime);
    }

}

再實現(xiàn)兼容的ViewAnimationCompatUtils


public class ViewAnimationCompatUtils {
    private static final String TAG = "ViewAnimationCompatUtil";

    public static Animator createCircularReveal(@NonNull View view, int centerX, int centerY, float startRadius, float endRadius) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            return ViewAnimationUtils.createCircularReveal(view, centerX, centerY, startRadius, endRadius);
        }

        //如果父view已經(jīng)是CircularRevealLayout,則設置參數(shù)后直接返回animator
        if (view.getParent() != null && view.getParent() instanceof CircularRevealLayout) {
            Log.e(TAG, "parent is CircularRevealLayout");
            CircularRevealLayout circularRevealLayout = (CircularRevealLayout) view.getParent();
            circularRevealLayout.setCenterX(centerX);
            circularRevealLayout.setCenterY(centerY);
            circularRevealLayout.setStartRadius(startRadius);
            circularRevealLayout.setEndRadius(endRadius);
            circularRevealLayout.setChildRevealView(view);
            return circularRevealLayout.getAnimator();
        }

        Log.e(TAG, "parent is not CircularRevealLayout");

        //如果父view不是CircularRevealLayout螟碎,則先為view添加父view CircularRevealLayout
        //之后將CircularRevealLayout替換掉原來的view
        CircularRevealLayout circularRevealLayout = new CircularRevealLayout(view.getContext());

        //開啟硬件加速
        circularRevealLayout.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

        circularRevealLayout.setCenterX(centerX);
        circularRevealLayout.setCenterY(centerY);
        circularRevealLayout.setStartRadius(startRadius);
        circularRevealLayout.setEndRadius(endRadius);
        circularRevealLayout.setChildRevealView(view);

        ViewGroup.LayoutParams params = view.getLayoutParams();
        ViewGroup parent = (ViewGroup) view.getParent();

        int index = 0;
        if (parent != null) {
            index = parent.indexOfChild(view);//記錄view在原先父view的下標
            Log.e(TAG, "index=" + index);
            parent.removeView(view);
            circularRevealLayout.addView(view, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
            parent.addView(circularRevealLayout, index, params);
        }
        return circularRevealLayout.getAnimator();
    }
}

寫到這兒眉菱,已經(jīng)能正常顯示了,不過在@Anderson大碼渣](http://www.reibang.com/p/d4b421795154)的基礎上我們最好再繼續(xù)做一定的修改掉分,上文在AnimationHelper的startActivityForResult中寫了個延遲任務俭缓,

 view.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        Animator anim = ViewAnimationCompatUtils.createCircularReveal(imageview, xCenter, yCenter, finalRadius, 0);
                        anim.setDuration(durationMills);
                        anim.addListener(new AnimatorListenerAdapter() {
                            @Override
                            public void onAnimationEnd(Animator animation) {
                                super.onAnimationEnd(animation);
                                try {
                                    decorView.removeView(imageview);
                                    imageview.setVisibility(View.GONE);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                        anim.start();
                    }
                }, 1000);

在4.0的系統(tǒng)上退回到前一個activity的時候動畫有時候會顯示不出來克伊,所以最在在baseactivity的onresume中寫一個回調,當回調時調用此動畫執(zhí)行华坦。

BaseActivity...

    @Override
    protected void onResume() {
        super.onResume();
        if (resume != null) {
            resume.setResume();
        }
    }

    public void setResume(IonResume resume) {
        this.resume = resume;
    }

    private IonResume resume;
    
    public interface IonResume {
        void setResume();
    }

...
thisActivity.setResume(new BaseActivity.IonResume() {
                    @Override
                    public void setResume() {
                        if (imageview.getVisibility()==View.VISIBLE){
                            Animator anim = ViewAnimationCompatUtils.createCircularReveal(imageview, xCenter, yCenter, finalRadius, 0);
                            anim.setDuration(800);
                            anim.addListener(new AnimatorListenerAdapter() {
                                @Override
                                public void onAnimationEnd(Animator animation) {
                                    super.onAnimationEnd(animation);
                                    try {
                                        decorView.removeView(imageview);
                                        imageview.setVisibility(View.GONE);
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                }
                            });
                            anim.start();
                        }
                    }
                });

Github代碼下載
也歡迎大家關注我的簡書愿吹、CSDN

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市惜姐,隨后出現(xiàn)的幾起案子犁跪,更是在濱河造成了極大的恐慌,老刑警劉巖歹袁,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坷衍,死亡現(xiàn)場離奇詭異,居然都是意外死亡条舔,警方通過查閱死者的電腦和手機枫耳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來逞刷,“玉大人嘉涌,你說我怎么就攤上這事妻熊】淝常” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵扔役,是天一觀的道長帆喇。 經(jīng)常有香客問我,道長亿胸,這世上最難降的妖魔是什么坯钦? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮侈玄,結果婚禮上婉刀,老公的妹妹穿的比我還像新娘。我一直安慰自己序仙,他們只是感情好突颊,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著潘悼,像睡著了一般律秃。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上治唤,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天棒动,我揣著相機與錄音,去河邊找鬼宾添。 笑死船惨,一個胖子當著我的面吹牛柜裸,可吹牛的內容都是我干的。 我是一名探鬼主播粱锐,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼粘室,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了卜范?” 一聲冷哼從身側響起衔统,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎海雪,沒想到半個月后锦爵,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡奥裸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年险掀,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片湾宙。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡樟氢,死狀恐怖,靈堂內的尸體忽然破棺而出侠鳄,到底是詐尸還是另有隱情埠啃,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布伟恶,位于F島的核電站碴开,受9級特大地震影響,放射性物質發(fā)生泄漏博秫。R本人自食惡果不足惜潦牛,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望挡育。 院中可真熱鬧巴碗,春花似錦、人聲如沸即寒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蒿叠。三九已至明垢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間市咽,已是汗流浹背痊银。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留施绎,地道東北人溯革。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓贞绳,卻偏偏與公主長得像,于是被迫代替她去往敵國和親致稀。 傳聞我的和親對象是個殘疾皇子冈闭,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內容