InstalMaterial學習筆記之Reveal效果

dapan發表於2021-09-09

本文記錄學習到的Reveal效果
國內有對應部落格的


先看一下效果圖:


圖片描述

最後效果圖

慣例,不過這次是我學到了什麼

  1. 對自定義屬性使用屬性動畫

  2. 屬性動畫,get方法不一定需要

  3. 最重要的是ViewTreeObserver.OnPreDrawListener()的使用,另一種過渡動畫的實現方式

OK,開始吧

首先

仔細看動畫效果,其實就是一個半徑不斷變大的圓

那麼來實現這個效果吧

  1. 先定義個類RevealView,過載構造方法

  2. 增加一個成員變數 radius 表示圓的半徑

  3. 增加一個Paint變數 mPaint 用來畫

如此後程式碼如下:

public RevealView(Context context) {    super(context);
    init();
}public RevealView(Context context, AttributeSet attrs) {    super(context, attrs);
    init();
}public RevealView(Context context, AttributeSet attrs, int defStyleAttr) {    super(context, attrs, defStyleAttr);
    init();
}private void init() {
    mPaint=new Paint();
    mPaint.setColor(getResources().getColor(R.color.primary_dark)); 
mPaint.setAntiAlias(true);
    mPaint.setStyle(Paint.Style.FILL);
}private Paint mPaint;private int radius;
接下來,我們重寫onDraw,畫個圓
@Overrideprotected void onDraw(Canvas canvas) {    
super.onDraw(canvas);    
//原點是中心    canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius, mPaint);
}

接下去就是讓radius得值不斷髮生變化了

到這裡,可能有同學會想著起個thread不停去賦值,再invalidate.
其實不必這麼麻煩,我們使用屬性動畫即可:

//這裡我計算了斜對角線的長度,這樣可以保證畫的圓能夠保證覆蓋整個viewint maxRadius = (int) (Math.sqrt(Math.pow(getHeight(), 2)+ Math.pow(getWidth(), 2)));
ObjectAnimator revealAnimator = ObjectAnimator.ofInt(this, "radius", 0,maxRadius).setDuration(300);
revealAnimator.setInterpolator(new AccelerateInterpolator());
revealAnimator.start();

到這裡熟悉屬性動畫的同學可能就知道,還差了getter setter方法
Tip:其實事實上getter方法不是必須的,少了setter方法也不會崩潰,只是動畫沒有效果而已
注意:

//Notice 這裡傳入了兩個值 如果只傳了一個,則會在動畫開始時候去呼叫gettter方法ObjectAnimator.ofInt(this, "radius", 0,maxRadius).setDuration(300);

OK,讓我們加入setter方法:

public void setRadius(int radius) {    this.radius = radius;
    Log.d(TAG, "setRadius "+radius);
}

恩,OK,問自己一下,這樣,就好了嗎?
答案是,沒有!
我們還需要對setter方法加工一下

public void setRadius(int radius) {    this.radius = radius;
    Log.d(TAG, "setRadius "+radius);    //Notice 呼叫invalidate 之後 onDraw才會被呼叫
    invalidate();
}

至此,我們執行一下:

圖片描述

reveal_效果1階段.gif

初始效果已經出來了,但是你會發現,動畫結束後,我們的revealview把其他View都擋住了.

呵呵,這個還不簡單嗎?動畫結束後給gone了不得了嘛?

//新增一個callback 回撥動畫結束public void setCallback(Callback callback) {    this.callback = callback;
}private Callback callback;public interface Callback{    void onRevealEnd();
}//在activity裡設定mVReveal.setCallback(new RevealView.Callback() {            @Override
            public void onRevealEnd() {//隱藏
                mVReveal.setVisibility(View.GONE);//                todo 其他事情
            }
        });

然後跑起來試試:


圖片描述

第一階段效果.gif

還不錯吧?

接下來我們運用到Activity跳轉

這個時候我們需要用到ViewTreeObserver.OnPreDrawListener()

//在跳轉的activity裡mVReveal.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {    @Override
    public boolean onPreDraw() {       //必須remove掉 不然會重複呼叫
        mVReveal.getViewTreeObserver().removeOnPreDrawListener(this);
        mVReveal.startReveal();        return false;
    }});

//按鈕點選事件

Intent intent = new Intent(this, RevealActivity.class);intent.putExtra("location", location);startActivity(intent);overridePendingTransition(0, 0);//Notice 這個絕對不能省..不然沒有效果

好了,差不多介紹到這裡..
不過其實還有其他的最佳化擴充套件,
1.比如傳座標,指定圓心開始reveal
2.reveal結束後繼續其他的動畫
大家自己試試吧:.

最後總結下

  1. InstalMaterial 是一個值得你認真去學習的開源專案.

  2. 時間允許的話一定要動手實踐,不要覺得看著簡單就以為自己會了,其實沒你想的那麼簡單.就像我,看著這個效果很簡單,原本覺得不用這麼麻煩就可以實現,結果,最後還是一步一步照著frogermcs的程式碼寫了下去,這樣才能真正學到東西.

  3. 自學不易,請堅持!

另外,最近在閱讀HeadFirst設計模式,尋找朋友一起學習交流~
下次見!~



作者:程式亦非猿
連結:

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/758/viewspace-2803091/,如需轉載,請註明出處,否則將追究法律責任。

相關文章