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 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!相關經驗