這篇文章的套路如下薄坏,帶你裝逼帶你飛。
- 概念
- 如何使用
- 設(shè)置 相同的名稱
- 啟動 startActivity
- Fragment to Fragment
- 設(shè)置多組元素
- 自定義過度動畫
- 源碼解讀
- 如何兼容低版本
先看一下 效果吧棍厂!
1.概念
在5.0之前侧馅,不同活動或片段的過渡是進(jìn)入和退出動畫,視圖層次結(jié)構(gòu)彼此獨立的轉(zhuǎn)換源葫。
過渡動畫則是:把兩個activity當(dāng)中的相同元素關(guān)聯(lián)起來做連貫的動畫; 從而達(dá)到不同視圖之間的元素關(guān)聯(lián)達(dá)到 酷炫雄坪、爆炸等酷炫而又優(yōu)雅地效果。
引導(dǎo)用戶視覺匹厘。
共享元素類型:
explode:從場景的中心移入或移出
slide:從場景的邊緣移入或移出
fade:調(diào)整透明度產(chǎn)生漸變效果
動畫效果:
changeBounds - 改變目標(biāo)視圖的布局邊界
changeClipBounds - 裁剪目標(biāo)視圖邊界
changeTransform - 改變目標(biāo)視圖的縮放比例和旋轉(zhuǎn)角度
changeImageTransform - 改變目標(biāo)圖片的大小和縮放比例
2. 如何使用
2.1 設(shè)置主題
先要在系統(tǒng)主題中設(shè)置主題嘀趟,或者在java代碼中設(shè)置支持過渡動畫的主題,我們在頁面切換時才有過渡動畫的效果愈诚,有以下兩種方式:
2.1.1 方法一
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
// 設(shè)置一個exit transition
getWindow().setExitTransition(new Explode());
可以通過如下方法在代碼總設(shè)置進(jìn)入與退出時 Transition 效果:
- Window.setEnterTransition():普通transition的進(jìn)入效果
- Window.setExitTransition():普通transition的退出效果
- Window.setSharedElementEnterTransition():共享元素transition的進(jìn)入效果
- Window.setSharedElementExitTransition():共享元素transition的退出效果
2.1.2 方法二
在xml中設(shè)置 默認(rèn)配置
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="android:windowContentTransitions">true</item>
<!-- 指定進(jìn)入和退出transitions -->
<item name="android:windowEnterTransition">@transition/explode</item>
<item name="android:windowExitTransition">@transition/explode</item>
<!-- 指定shared element transitions -->
<item name="android:windowSharedElementEnterTransition">
@transition/change_image_transform</item>
<item name="android:windowSharedElementExitTransition">
@transition/change_image_transform</item>
...
</style>
2.2 設(shè)置 相同的名稱
共享元素切換她按,首先要保證兩個頁面內(nèi)view的transitionName
是一致的
設(shè)置:android:transitionName
如下:
MainActivity.xml
<android.support.v7.widget.CardView
...>
<ImageView
android:id="@+id/ivProfile"
android:transitionName="profile"
android:scaleType="centerCrop"
android:layout_width="match_parent"
android:layout_height="160dp" />
...
</android.support.v7.widget.CardView>
DetailActivity.xml
<LinearLayout
...>
<ImageView
android:id="@+id/ivProfile"
android:transitionName="profile"
android:scaleType="centerCrop"
android:layout_width="match_parent"
android:layout_height="380dp" />
...
</LinearLayout>
2.3 啟動 startActivity
第一個Acitivty執(zhí)行頁面跳轉(zhuǎn)時需要加上 ActivityOptionsCompat.toBundle()
才會顯示出過渡動畫的效果
Intent intent = new Intent(this, DetailsActivity.class);
// Pass data object in the bundle and populate details activity.
intent.putExtra(DetailsActivity.EXTRA_CONTACT, contact);
//
getWindow().setExitTransition(new Explode()); //設(shè)置頁面切換效果
//第一次進(jìn)入時使用
getWindow().setEnterTransition(new explode);
//再次進(jìn)入時使用
getWindow().setReenterTransition(new explode);
Transition ts = new ChangeClipBounds(); //設(shè)置元素動畫
ts.setDuration(3000);
getWindow().setSharedElementExitTransition(ts);
ActivityOptionsCompat options = ActivityOptionsCompat.
makeSceneTransitionAnimation(this, (View)ivProfile, "profile");
startActivity(intent, options.toBundle());
從第二個Activity反轉(zhuǎn)場景轉(zhuǎn)換動畫勋桶,請調(diào)用Activity.supportFinishAfterTransition()而不是Activity.finish()汁尺,如果你使用了toolbar的返回按鈕行為疟呐,也需要去覆蓋它
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
case android.R.id.home:
supportFinishAfterTransition();
return true;
}
return super.onOptionsItemSelected(item);
}
2.4 Fragment to Freagment
// Get access to or create instances to each fragment
FirstFragment fragmentOne = ...;
SecondFragment fragmentTwo = ...;
// Check that the device is running lollipop
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// Inflate transitions to apply
Transition changeTransform = TransitionInflater.from(this).
inflateTransition(R.transition.change_image_transform);
Transition explodeTransform = TransitionInflater.from(this).
inflateTransition(android.R.transition.explode);
// Setup exit transition on first fragment
fragmentOne.setSharedElementReturnTransition(changeTransform);
fragmentOne.setExitTransition(explodeTransform);
// Setup enter transition on second fragment
fragmentTwo.setSharedElementEnterTransition(changeTransform);
fragmentTwo.setEnterTransition(explodeTransform);
// Find the shared element (in Fragment A)
ImageView ivProfile = (ImageView) findViewById(R.id.ivProfile);
// Add second fragment by replacing first
FragmentTransaction ft = getFragmentManager().beginTransaction()
.replace(R.id.container, fragmentTwo)
.addToBackStack("transaction")
.addSharedElement(ivProfile, "profile");
// Apply the transaction
ft.commit();
}
else {
// Code to run on older devices
}
2.6 設(shè)置多組元素
如最開始的展示效果豆挽,可以知道,我們是可以設(shè)置多組元素的關(guān)聯(lián)并且對每個元素可以執(zhí)行不同的過渡動畫的挖胃,它的方式如下:
Intent intent = new Intent(context, DetailsActivity.class);
intent.putExtra(DetailsActivity.EXTRA_CONTACT, contact);
Pair<View, String> p1 = Pair.create((View)ivProfile, "profile");
Pair<View, String> p2 = Pair.create(vPalette, "palette");
Pair<View, String> p3 = Pair.create((View)tvName, "text");
ActivityOptionsCompat options = ActivityOptionsCompat.
makeSceneTransitionAnimation(this, p1, p2, p3);
startActivity(intent, options.toBundle());
注意:默認(rèn)情況下android.util.Pair將被導(dǎo)入啃洋,但是我們要選擇android.support.v4.util.Pair類碾盐。
這里要避免元素過多導(dǎo)致分散注意力的動畫欢嘿,這樣可能會失去過渡動畫的意義衰琐。
3.自定義過度動畫
本質(zhì)上就是重寫 Transition;
套路如下:
1炼蹦、繼承 Visibility 或者 Transition
2羡宙、自定義動畫:實現(xiàn) VIsibility/Transition內(nèi)方法
3、在頁面中將自定義Transition設(shè)入:getWindow().setEnterTransition
或者setSharedElementEnterTransition
看一下自定義的效果
3.1 一些概念:
- Visibility extends Transition 頁面切換轉(zhuǎn)場動畫類掐隐;
- shareView 的移動的軌跡路徑PathMotion類
ArcMotion arcMotion = new ArcMotion();
arcMotion.setMinimumHorizontalAngle(50f);
arcMotion.setMinimumVerticalAngle(50f);
3.2 自定義動畫
繼承 Visibility:
public void captureStartValues(TransitionValues transitionValues) 這里保存計算動畫初始狀態(tài)的一個屬性值
public void captureEndValues(TransitionValues transitionValues) 這里保存計算動畫結(jié)束狀態(tài)的一個屬性值
public Animator onAppear(ViewGroup sceneRoot, final View view, TransitionValues startValues, TransitionValues endValues)
如果是進(jìn)入動畫 即顯示某個 View 則會執(zhí)行這個方法
public Animator onDisappear(ViewGroup sceneRoot, final View view, TransitionValues startValues, TransitionValues endValues)
如果是退出 , VIew 則會執(zhí)行這個方法
繼承 Transition:
@Override
public void captureStartValues(TransitionValues transitionValues) {
//初始值保存
}
@Override
public void captureEndValues(TransitionValues transitionValues) {
//結(jié)束值保存
}
createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues){
//創(chuàng)建執(zhí)行動畫
}
3.3 調(diào)用
getWindow().setEnterTransition(new CommentEnterTransition(this, toolbar, bottom_aty_love));//設(shè)置
getWindow().setSharedElementEnterTransition(buildShareElemEnterSet());//設(shè)置進(jìn)入轉(zhuǎn)換動畫
getWindow().setSharedElementReturnTransition(buildShareElemReturnSet());//設(shè)置退出轉(zhuǎn)換動畫
自定義過渡動畫的Activity:https://github.com/LidongWen/LittlePrincess/blob/master/app/src/main/java/com/wenld/littleprincess/activity/LoveActivity.java
4. 源碼解讀
帶著幾個疑問:
- Transition內(nèi)方法在哪里被調(diào)用
- 看一個 系統(tǒng) 的 轉(zhuǎn)換類寫法 狗热,這邊選擇
Explode
- 在
TransitionKitKat
內(nèi)被調(diào)用
@Override
public void captureEndValues(TransitionValues transitionValues) {
android.transition.TransitionValues internalValues =
new android.transition.TransitionValues();
copyValues(transitionValues, internalValues);
mTransition.captureEndValues(internalValues);
copyValues(internalValues, transitionValues);
}
@Override
public void captureStartValues(TransitionValues transitionValues) {
android.transition.TransitionValues internalValues =
new android.transition.TransitionValues();
copyValues(transitionValues, internalValues);
mTransition.captureStartValues(internalValues);
copyValues(internalValues, transitionValues);
}
@Override
public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
TransitionValues endValues) {
android.transition.TransitionValues internalStartValues;
android.transition.TransitionValues internalEndValues;
if (startValues != null) {
internalStartValues = new android.transition.TransitionValues();
copyValues(startValues, internalStartValues);
} else {
internalStartValues = null;
}
if (endValues != null) {
internalEndValues = new android.transition.TransitionValues();
copyValues(endValues, internalEndValues);
} else {
internalEndValues = null;
}
return mTransition.createAnimator(sceneRoot, internalStartValues, internalEndValues);
}
Explode源碼
- Explode結(jié)構(gòu)如下:
public class Explode extends Visibility {
public Explode() {
setPropagation(new CircularPropagation());
}
private void captureValues(TransitionValues transitionValues) {
}
//初始值
@Override
public void captureStartValues(TransitionValues transitionValues) {
super.captureStartValues(transitionValues);
captureValues(transitionValues);
}
//結(jié)束值
@Override
public void captureEndValues(TransitionValues transitionValues) {
super.captureEndValues(transitionValues);
captureValues(transitionValues);
}
// 進(jìn)入時被調(diào)用
@Override
public Animator onAppear(ViewGroup sceneRoot, View view,
TransitionValues startValues, TransitionValues endValues) {
//執(zhí)行動畫
return TranslationAnimationCreator.createAnimation(view, endValues, bounds.left, bounds.top,
startX, startY, endX, endY, sDecelerate, this);
}
//退出頁面時調(diào)用
@Override
public Animator onDisappear(ViewGroup sceneRoot, View view,
TransitionValues startValues, TransitionValues endValues) {
return TranslationAnimationCreator.createAnimation(view, startValues,
viewPosX, viewPosY, startX, startY, endX, endY, sAccelerate, this);
}
private void calculateOut(View sceneRoot, Rect bounds, int[] outVector) {
}
}
太簡單了,虑省,就是調(diào)用 TranslationAnimationCreator.createAnimation
創(chuàng)建動畫....,我們上面的自定義過渡動畫就是跟 這貨學(xué)習(xí)到....
5. 兼容低版本
到了這里匿刮, 送大家一首歌:感覺身體被掏空.......
由于復(fù)雜度的原因,
低版本兼容還是說下思路吧探颈,以后有時間或者有明確需求在去實現(xiàn):
思路:
- 將第一個頁面中共享元素拿出保存熟丸。
- 在第二個頁面的onCreate()方法內(nèi),設(shè)置動畫膝擂,并執(zhí)行第一個頁面view的動畫虑啤。
- 第二個界面退出時,執(zhí)行第二個界面共享元素動畫架馋。
大玩一發(fā)——MaterialDesign元素轉(zhuǎn)換動畫兼容低版本(有可能不會寫D健)
網(wǎng)絡(luò)上有人實現(xiàn)過 大概是這種思路:https://github.com/huzenan/EasyTransition,具體代碼我沒運行過叉寂,不過目測應(yīng)該是可行的萍启。
參考:
- https://github.com/codepath/android_guides/wiki/Shared-Element-Activity-Transition
- http://www.bkjia.com/Androidjc/900882.html
- http://www.reibang.com/p/37e94f8b6f59
- http://www.reibang.com/p/cc6cb29ec298
- http://www.open-open.com/lib/view/open1477879867267.html
demo地址:戳我!!!
希望我的文章不會誤導(dǎo)在觀看的你,如果有異議的地方歡迎討論和指正屏鳍。
如果能給觀看的你帶來收獲勘纯,那就是最好不過了。