編輯:關於Android編程
前言
在 Android 5.0 之前,我們已經有了 overridePendingTransition()
方法來實現一些轉場效果。然而,在 Android 5.0 以後,轉場效果更加炫酷。
比如下面的動畫:
一、Android L 中的轉場動畫
實現轉場動畫只需三步:
在 res/ 目錄下創建 transition 文件夾,在該文件夾下定義界面轉場動畫和共享元素的動畫。
在 res/value/style 文件中為每個 Activity 指定轉場動畫的 style ,並在 AndroidManifest.xml 文件中為每個 Activity 設置對應的 android:theme。
在 Activity 調用 startActivity()
切換動畫前,使用 ActivityOptionsCompat 來創建轉場動畫時的共享對象。
下面就來對這三步進行詳細講解。
二、定義轉場動畫
在 res/ 目錄下創建了 transition 資源文件夾後,就可以在該文件夾下對每一種動畫進行定義。
一般來說,對 Activity 定義一個過渡動畫可以寫成下面的形式:
<explode xmlns:android="http://schemas.android.com/apk/res/android"> <targets> <target android:excludeId="@android:id/statusBarBackground"/> <target android:excludeId="@android:id/navigationBarBackground"/> </targets> </explode>
其中, 是動畫效果的名稱,Android 5.0(API 級別 21)支持這些進入與退出轉換:
1、分解(explode):從場景中心移入或移出視圖。
2、滑動(slide):從場景邊緣移入或移出視圖。
3、淡入淡出(fade):通過調整透明度在場景中增添或移除視圖。
而每一種動畫效果,都有額外的屬性。比如滑動 slide,可以使用 android:slideEdge="top"
設置滑動的方向;淡入淡出(fade)可以使用 android:fadingMode="fade_in"
設置具體是淡入(fade_in)還是淡出(fade_out)等。
標簽裡面定義需要轉場(或者不需要轉場)的目標 id ,這個 id 可以使系統自帶的,也可以是我們自己視圖中的 view 的 id,每一個 id 需要單獨在 標簽中定義,android:targetId
表示目標ID需要進行過渡轉換的 view,而 android:excludeId
表示我們不需要該 ID 的 view 進行過渡轉場。上面的那段代碼的意思是說,除了狀態欄和導航欄以外所有的 view,都執行 explode 動畫。
如果我們想要在同一個過渡狀態中實現兩種或多種動畫效果怎麼辦?也簡單,將根標簽替換為 ,然後定義每一種動畫效果,最後記得在根標簽中使用 android:transitionOrdering
注明這幾種動畫的演示順序,sequential 表示順序執行,而 together 表示同時執行。
比如像下面的代碼:
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"> <slide android:slideEdge="bottom"> <targets> <target android:targetId="@id/cardview"/> </targets> </slide> <fade> <targets> <target android:excludeId="@android:id/statusBarBackground"/> <target android:excludeId="@android:id/navigationBarBackground"/> <target android:excludeId="@id/cardview"/> </targets> </fade> </transitionSet>
這段代碼的意思就很簡單了,該 xml 定義了兩個過渡動畫,並且同時執行。第一個動畫是針對 id 為 cardView 的 view 進行滑動,第二個動畫將除了狀態欄、導航欄和 cardview 以外的 view,進行淡入淡出。
三、為每個 Activity 定義轉場樣式
這裡的每一種動畫,指的是在進行界面跳轉過渡時,兩個界面的狀態。比如對於 Activity A 和 Activity B 這兩個界面,可能的狀態如下:
1、界面 A 跳轉至界面 B :這時界面 A 是退出(exit )過渡狀態,而對應的界面B是進入(enter)過渡狀態。
2、界面 B 返回到界面 A :這時界面 A 是重新進入(reenter)過渡,而對應的界面B則是返回(return)過渡。
一般來說,所有的 Activity 過渡動畫都可以定義成如下的形式:
<style name="BaseAppTheme" parent="android:Theme.Material"> <!-- 開啟過渡效果 --> <item name="android:windowContentTransitions">true</item> <!-- 指定界面進入/退出動畫效果 --> <item name="android:windowEnterTransition">@transition/explode</item> <item name="android:windowExitTransition">@transition/explode</item> <!-- 指定共享元素進入/退出的動畫效果 --> <item name="android:windowSharedElementEnterTransition"> @transition/change_image_transform</item> <item name="android:windowSharedElementExitTransition"> @transition/change_image_transform</item> </style>
當然,你可以不用寫全,比如在我的 Demo 中一個界面的轉場動畫文件如下:
<style name="AppTheme.Detail"> <item name="windowActionBar">false</item> <item name="android:windowNoTitle">true</item> <item name="android:windowTranslucentStatus">true</item> <item name="android:windowAllowEnterTransitionOverlap">false</item> <item name="android:windowEnterTransition">@transition/detail_enter</item> </style>
四、調用 ActivityOptionsCompat
轉場動畫是在兩個界面的跳轉返回時發生的,所以,當使用 intent 跳轉界面時,需要調用 ActivityOptionsCompat來指定動畫的運行。
一般來說,調用 ActivityOptionsCompat 的模板代碼如下:
// 創建一個包含過渡動畫信息的 ActivityOptions 對象 ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this, view, getString(R.string.image_transition_name)); // 使用 Intent 跳轉界面,並傳遞共享對象信息 Intent intent = new Intent(this, DetailActivity.class); startActivity(intent, optionsCompat.toBundle());
ActivityOptionsCompat 是在support v4 包裡面的,其實它是 ActivityOptions 的一個兼容(ActivityOptions是API 16引入的)。
然後,我們需要在第二個 Activity 中,將轉場的圖片獲取並顯示到界面中。
多個共享元素的過渡實現
有時候我們需要讓多個元素產生動畫效果,可以使用 Pair<> 來實現:
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this, Pair.create(view1, "agreedName1"), Pair.create(view2, "agreedName2"));
五、手動實現一個轉場動畫
現在市面上,Android 5.0 以下的手機系統還有一定的市場份額,所以為了照顧這些用戶,我們只能手動實現一下共享元素的轉場動畫效果。
實現的思路也比較簡單,大概的步驟如下:
1、確定第一個界面的共享元素,將其信息傳遞個第二個界面
2、第二個界面接收信息,開始的時候將界面設置為透明,並只顯示共享元素。
3、將第二個界面的共享元素進行動畫處理。
那麼我們開始一步步實現上面的步驟。
獲取共享元素位置信息
在第一個界面中,我們需要獲取到共享元素的位置信息,並將其傳遞給下一個界面。於是乎,我們可以在第一個界面元素點擊事件中,這麼寫:
public void imageClick(View view) { Intent intent = new Intent(AnimeActivity.this, AnimeDetailActivity.class); // 創建一個 rect 對象來存儲共享元素位置信息 Rect rect = new Rect(); // 獲取元素位置信息 view.getGlobalVisibleRect(rect); // 將位置信息附加到 intent 上 intent.setSourceBounds(rect); CustomImage customImage = (CustomImage) view; intent.putExtra(AnimeDetailActivity.EXTRA_IMAGE, customImage.getImageId()); startActivity(intent); // 屏蔽 Activity 默認轉場效果 overridePendingTransition(0, 0); }
其中,getGlobalVisibleRect()
方法的含義是,獲取 可見的狀態欄高度+可見的標題欄高度+Rect左上角到標題欄底部的距離,如果標題欄被隱藏了,那麼可見標題欄高度為0。
接下來,就在在第二個界面接收位置信息並將該圖片展示出來了。
模擬轉場動畫
在第二個界面中,我們需要做如下的操作:
1、獲取上共享元素信息。
2、計算共享元素縮放比例和位移距離。
3、調用動畫,完成模擬轉場效果。
我將上面三個步驟的代碼如下。
private void initial() { // 獲取上一個界面傳入的信息 mRect = getIntent().getSourceBounds(); mRescourceId = getIntent().getExtras().getInt(EXTRA_IMAGE); // 獲取上一個界面中,圖片的寬度和高度 mOriginWidth = mRect.right - mRect.left; mOriginHeight = mRect.bottom - mRect.top; // 設置 ImageView 的位置,使其和上一個界面中圖片的位置重合 FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(mOriginWidth, mOriginHeight); params.setMargins(mRect.left, mRect.top - getStatusBarHeight(), mRect.right, mRect.bottom); mImageView.setLayoutParams(params); // 設置 ImageView 的圖片和縮放類型 mImageView.setImageResource(mRescourceId); mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP); // 根據上一個界面傳入的圖片資源 ID,獲取圖片的 Bitmap 對象。 BitmapDrawable bitmapDrawable = (BitmapDrawable) getResources().getDrawable(mRescourceId); Bitmap bitmap = bitmapDrawable.getBitmap(); // 計算圖片縮放比例和位移距離 getBundleInfo(bitmap); // 創建一個 Pallette 對象 mImagePalette = Palette.from(bitmap).generate(); // 使用 Palette 設置背景顏色 mContainer.setBackgroundColor( mImagePalette.getVibrantColor(ContextCompat.getColor(this, android.R.color.black))); }
在12行,通過設置 Margin 的形式來確定圖片的位置,需要注意的是,由於狀態欄是在父控件 FramLayout 之外的,因此我們要將 Rect.top 的值減去狀態欄的高度,這樣才是相對於屏幕的絕對位置。然後,getBundleInfo()
方法的代碼如下:
private void getBundleInfo(Bitmap bitmap) { // 計算圖片縮放比例,並存儲在 bundle 中 if (bitmap.getWidth() >= bitmap.getHeight()) { mScaleBundle.putFloat(SCALE_WIDTH, (float) mScreenWidth / mOriginWidth); mScaleBundle.putFloat(SCALE_HEIGHT, (float) bitmap.getHeight() / mOriginHeight); } else { mScaleBundle.putFloat(SCALE_WIDTH, (float) bitmap.getWidth() / mOriginWidth); mScaleBundle.putFloat(SCALE_HEIGHT, (float) mScreenHeight / mOriginHeight); } // 計算位移距離,並將數據存儲到 bundle 中 mTransitionBundle.putFloat(TRANSITION_X, mScreenWidth / 2 - (mRect.left + (mRect.right - mRect.left) / 2)); mTransitionBundle.putFloat(TRANSITION_Y, mScreenHeight / 2 - (mRect.top + (mRect.bottom - mRect.top) / 2)); }
動畫處理
最後我們需要使用動畫來模擬轉場效果,代碼如下:
private void runEnterAnim() { mImageView.animate() .setInterpolator(DEFAULT_INTERPOLATOR) .setDuration(DURATION) .scaleX(mScaleBundle.getFloat(SCALE_WIDTH)) .scaleY(mScaleBundle.getFloat(SCALE_HEIGHT)) .translationX(mTransitionBundle.getFloat(TRANSITION_X)) .translationY(mTransitionBundle.getFloat(TRANSITION_Y)) .start(); }
很簡單,自此,入場動畫效果基本模擬完畢。
而退場動畫就更簡單了,直接上代碼:
private void runExitAnim() { mImageView.animate() .setInterpolator(DEFAULT_INTERPOLATOR) .setDuration(DURATION) .scaleX(1) .scaleY(1) .translationX(0) .translationY(0) .withEndAction(new Runnable() { @Override public void run() { finish(); overridePendingTransition(0, 0); } }) .start(); }
總結
以上就是Android中實現轉場動畫的全部內容,所以,是不是很簡單?希望這篇文章的內容對各位Android開發者們能有所幫助,如果有疑問大家可以留言交流。
效果圖知識點分析效果圖來看不復雜內容並沒多少,值得介紹一下的知識點也就下面幾個吧- 列表標題懸停- 左右列表滑動時聯動- 添加商品時的拋物線動畫- 底部彈出購物車清單-
作為開發者我們需要經常站在用戶角度考慮問題,比如在應用商城下載軟件時,當用戶點擊下載按鈕,則會有下載進度提示頁面出現,現在我們通過線程休眠的方式模擬下載進度更新的演示,如
大家購買小米手環之後使用最多的大概就是來電提醒和檢測運動量這兩個功能了,但是很多朋友說小米手環經常抽風,來電不震動。那麼小米手環來電不震動這種情況是怎麼回事
當你在QQ空間直播開啟直播後,會收到粉絲們的禮物,也就是星星。這些星星可以兌換成收益直接提現嗎?其實這些都是可以提取出來的現金,那麼下面小編教大家QQ空間直
Android 開發工具升級到22.6.2在創建工程時只要選擇的最低版本