InstalMaterial學習筆記之Reveal效果
本文記錄開源項目 InstalMaterial學習到的Reveal效果
國內有對應博客的翻譯
先看一下效果圖:

慣例,不過這次是我學到了什么
- 對自定義屬性使用屬性動畫
- 屬性動畫,get方法不一定需要
- 最重要的是ViewTreeObserver.OnPreDrawListener()的使用,另一種過渡動畫的實現方式 </ol>
- 先定義個類RevealView,重載構造方法
- 增加一個成員變量 radius 表示圓的半徑
- 增加一個Paint變量 mPaint 用來畫 </ol>
OK,開始吧
首先
仔細看動畫效果,其實就是一個半徑不斷變大的圓
那么來實現這個效果吧
如此后代碼如下:
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;</pre>
接下來,我們重寫onDraw,畫個圓
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//原點是中心
canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius, mPaint);
} 接下去就是讓radius得值不斷發生變化了
到這里,可能有同學會想著起個thread不停去賦值,再invalidate.
其實不必這么麻煩,我們使用屬性動畫即可:
//這里我計算了斜對角線的長度,這樣可以保證畫的圓能夠保證覆蓋整個view
int 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
</div>
初始效果已經出來了,但是你會發現,動畫結束后,我們的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 其他事情
}
});</pre>
然后跑起來試試:

第一階段效果.gif
</div>
還不錯吧?
接下來我們運用到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結束后繼續其他的動畫
大家自己試試吧:Github.
最后總結下
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!
相關經驗