Activity 切換動畫(小米圖庫列表進入詳情頁,圖片從固定位置放大進入,縮小退出),
直接上
ok,來分析下如何?的吧
分析原理
首先確定,這是兩個不同的 Activity,從圖片列表頁跳入到圖片詳情頁;先來看進入詳情頁時的動畫,從列表中所在 item 的位置一直放大到詳情頁的顯示位置,這裡我可以先告訴大家,當我們點擊了這個 item 的時候,就已經啟動了詳情頁,然後在詳情頁做相應的動畫效果。既然是在詳情頁做動畫效果,就需要在列表頁把相應的值傳過去,列表頁 item 在螢幕上的位置,item 的大小,當然還有圖片的資源,然後在詳情頁計算動畫執行的參數。分析了進入動畫,那麼退出 Activity 的動畫就好實現了,跟進入動畫相反,但是也是要確定什麼時候執行退齣動畫,這裡退齣動畫也是放在詳情頁面實現的,當按下返回按鈕時,開始執行退齣動畫,在動畫執行完之後,把詳情頁的 Activity 結束掉;大家會問了,可以把動畫放在列表頁執行嗎?大家仔細想一下就知道,如果是進入動畫,肯定是不能的,因為詳情頁沒有啟動,有些參數無法知道,比如放大到多大,放大以後的位置是哪裡等,但是退齣動畫是可以的,但比較麻煩,需要把詳情頁的參數返回給列表頁,如果有興趣可以試著做一下。
效果實現
1、傳入詳情頁的參數擷取
@Override public void onItemClick(View view) { int location[] = new int[2] ; view.getLocationOnScreen(location); int resId = (int) view.getTag(); Bundle bundle = new Bundle() ; bundle.putInt("locationX",location[0]); bundle.putInt("locationY",location[1]); bundle.putInt("width",view.getWidth()); bundle.putInt("height",view.getHeight()); bundle.putInt("resId",resId); Intent intent = new Intent() ; intent.putExtras(bundle); intent.setClass(getActivity(),PicDetailActivity.class) ; getActivity().startActivity(intent); getActivity().overridePendingTransition(0, 0); Log.v("zgy","========view========"+view.getWidth()) ; }
item 在螢幕中的座標,可以通過
int location[] = new int[2] ;view.getLocationOnScreen(location);
來擷取,記得把 Activity 的切換動畫去掉
getActivity().overridePendingTransition(0, 0);
2、進入動畫參數的 擷取
擷取列表頁傳入的值
final int left = getIntent().getIntExtra("locationX", 0); final int top = getIntent().getIntExtra("locationY", 0); final int width = getIntent().getIntExtra("width", 0); final int height = getIntent().getIntExtra("height", 0); int resId = getIntent().getIntExtra("resId", 0);
計算動畫執行的參數
mImageView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { mImageView.getViewTreeObserver().removeOnPreDrawListener(this); int location[] = new int[2]; mImageView.getLocationOnScreen(location); mLeft = left - location[0]; mTop = top - location[1]; mScaleX = width*1.0f / mImageView.getWidth(); mScaleY = height*1.0f / mImageView.getHeight(); Log.v("zgy", "========resId========" + mImageView.getWidth()) ; Log.v("zgy", "========resId========" + mScaleY) ; activityEnterAnim(); return true; } });
因為是在 OnCreate方法中執行的,不能直接擷取的 View 的大小,因為這時 View 尚未測量完成,需要功過監聽 View 的繪製來擷取,這裡計算當前 顯示的 View 距離列表 View 的距離及放縮比例;
3、設定動畫開始執行的位置
mImageView.setPivotX(0); mImageView.setPivotY(0); mImageView.setScaleX(mScaleX); mImageView.setScaleY(mScaleY); mImageView.setTranslationX(mLeft); mImageView.setTranslationY(mTop);
4、開始執行進入動畫
這個時候已經啟動了 詳情頁面,所以執行動畫以後不需要做任何操作了
mImageView.animate().scaleX(1).scaleY(1).translationX(0).translationY(0). setDuration(1000).setInterpolator(new DecelerateInterpolator()).start(); ObjectAnimator objectAnimator = ObjectAnimator.ofInt(mBackground,"alpha",0,255); objectAnimator.setInterpolator(new DecelerateInterpolator()); objectAnimator.setDuration(1000); objectAnimator.start();
來看看這時候的
5、退齣動畫
mImageView.setPivotX(0); mImageView.setPivotY(0); mImageView.animate().scaleX(mScaleX).scaleY(mScaleY).translationX(mLeft).translationY(mTop). withEndAction(runnable). setDuration(1000).setInterpolator(new DecelerateInterpolator()).start(); ObjectAnimator objectAnimator = ObjectAnimator.ofInt(mBackground,"alpha",255,0); objectAnimator.setInterpolator(new DecelerateInterpolator()); objectAnimator.setDuration(1000); objectAnimator.start();
這裡在動畫結束的時候傳入了一個 Runnable 對象,這個 Runnable 的作用就是結束詳情頁面
activityExitAnim(new Runnable() { @Override public void run() { finish(); overridePendingTransition(0, 0); } });
當你正在動手做的時候你可能會發現這樣一個現象,來看看
為什麼會這樣?我前面寫了一遍 blog 手勢滑動結束 Activity(一)準系統的實現,看完你就明白了。
總結
這篇 blog 的內容也不多,實現起來頁不難,只是看大家能不能想到。當然還是涉及到部分知識點:
1、屬性動畫的運用,
2、View 在螢幕上位置的擷取,可以通過
int location[] = new int[2] ;
View.getLocationOnScreen(location);
3、在 onCreate 中測量 View 的大小,不能直接擷取,需要監聽 View 的繪製,或者其他測量完成之後的回掉介面。
點擊 下載源碼