在Fragment之间进行动画导航的方式有两种:
1.使用Animation
或者animator
框架;
2.使用Transition框架
术语:
- enter effect :进入效果。A跳转到B界面,B界面(入场)的变化效果。
- exit effect :退出效果。A跳转到B界面,A界面(退场)的变化效果。
-
popEnter
:B界面返回到A界面,A界面(重入场)的变化效果。 -
popExit
:B界面返回到A界面,AB界面(退场)的变化效果。 - shared element transition: 共享元素动画。AB界面中有共享元素,对此元素的入场(退场)进行动画效果。
用动画框架( Animation Framework)
和平常使用Animation一样,我们需要首先定义资源文件。
<!-- res/anim/fade_out.xml -->
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_shortAnimTime"
android:interpolator="@android:anim/decelerate_interpolator"
android:fromAlpha="1"
android:toAlpha="0" />
<!-- res/anim/slide_in.xml -->
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_shortAnimTime"
android:interpolator="@android:anim/decelerate_interpolator"
android:fromXDelta="100%"
android:toXDelta="0%" />
返回时的界面效果同理:
<!-- res/anim/slide_out.xml -->
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_shortAnimTime"
android:interpolator="@android:anim/decelerate_interpolator"
android:fromXDelta="0%"
android:toXDelta="100%" />
<!-- res/anim/fade_in.xml -->
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_shortAnimTime"
android:interpolator="@android:anim/decelerate_interpolator"
android:fromAlpha="0"
android:toAlpha="1" />
最后Fragment跳转时,在 [FragmentTransaction.setCustomAnimations()
]中使用他们即可。
val fragment = FragmentB()
supportFragmentManager.commit {
setCustomAnimations(
enter = R.anim.slide_in,
exit = R.anim.fade_out,
popEnter = R.anim.fade_in,
popExit = R.anim.slide_out
)
replace(R.id.fragment_container, fragment)
addToBackStack(null)
}
用过渡框架(Transition Fragment)
For example, you might want the current fragment to fade out and the new fragment to slide in from the right edge of the screen.
<!-- res/transition/fade.xml -->
<fade xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_shortAnimTime"/>
<!-- res/transition/slide_right.xml -->
<slide xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_shortAnimTime"
android:slideEdge="right" />
使用的时候则是,在A界面(出场界面)中调用setExitTransition()
;
在B界面(入场界面)中调用 setEnterTransition()
。
class FragmentA : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val inflater = TransitionInflater.from(requireContext())
exitTransition = inflater.inflateTransition(R.transition.fade)
}
}
class FragmentB : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val inflater = TransitionInflater.from(requireContext())
enterTransition = inflater.inflateTransition(R.transition.slide_right)
}
}
共享元素动画
- 首先,还是定义xml。
<!-- res/transition/shared_image.xml -->
<transitionSet
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1375"
android:transitionOrdering="together">
<changeClipBounds/>
<changeTransform/>
<changeBounds/>
<changeImageTransform/>
</transitionSet>
- 其次,要在A B界面中分别标明哪个是共享的元素.用
setTransitionName(view, "name")
class FragmentA : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
...
val itemImageView = view.findViewById<ImageView>(R.id.item_image)
ViewCompat.setTransitionName(itemImageView, “item_image”)
}
}
class FragmentB : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
...
val heroImageView = view.findViewById<ImageView>(R.id.hero_image)
ViewCompat.setTransitionName(heroImageView, “hero_image”)
}
}
- 当然,FragmentTransaction也要认得这个动画的共享元素:【
FragmentTransaction.addSharedElement()
】
val fragment = FragmentB()
supportFragmentManager.commit {
setCustomAnimations(...)
addSharedElement(itemImageView, “hero_image”)
replace(R.id.fragment_container, fragment)
addToBackStack(null)
}
- 最后,要用到第一步中定义的shared_image动画。
通过TransitionInflater
把xml转为对象,再在B界面(跳转到的界面)中用Fragment.setSharedElementEnterTransition()
即可。
class FragmentB : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
sharedElementEnterTransition = TransitionInflater.from(requireContext())
.inflateTransition(R.transition.shared_image)
}
}