Понимание фрагментов в Android: часть 3
23 ноября 2022 г.В этой статье мы разберем интересные моменты анимации Fragment API.
Вы можете прочитать предыдущие части статьи по ссылке ниже.
Мы можем определить простые анимации для переходов между фрагментами в папке res/anim. Но если мы хотим управлять какими-либо атрибутами представления нашего фрагмента, мы должны указать анимации в папке res/animator. Более того, мы можем легко комбинировать их внутри транзакции.
fragmentManager.commit {
setReorderingAllowed(true)
// Must be specified before add/replace otherwise they will be ignored
setCustomAnimations(
R.animator.anim_enter, // InnerFragment appears on the screen
R.anim.anim_exit, // OuterFragment goes off screen
R.anim.anim_pop_enter, // OuterFragment returns to screen
R.animator.anim_pop_exit // InnerFragment goes off screen
)
replace<InnerFragment>(R.id.container)
addToBackStack(null)
}
Эти анимации автоматически применяются ко всем последующим транзакциям с использованием этого fragmentManager
.
<!-- animator/anim_enter.xml -->
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="400"
android:valueFrom="0"
android:valueTo="180"
android:propertyName="rotation" />
<!-- anim/anim_exit.xml -->
<alpha
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="400"
android:interpolator="@android:anim/decelerate_interpolator"
android:fromAlpha="1"
android:toAlpha="0" />
<!-- anim/anim_pop_enter.xml -->
<alpha
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="400"
android:interpolator="@android:anim/decelerate_interpolator"
android:fromAlpha="0"
android:toAlpha="1" />
<!-- animator/anim_pop_exit.xml -->
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="400"
android:valueFrom="180"
android:valueTo="360"
android:propertyName="rotation" />
Если не хотите прописывать каждую анимацию, можно использовать Transition — например, подготовленный Fade() . Он указан в InnerFragment
и переопределяет анимацию в транзакции, если она была указана.
// InnerFragment.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Animation when moving to the screen
enterTransition = Fade()
// Animation when leaving the screen via fragmentManager.popBackStack()
// If not specified, will be used
enterTransition exitTransition = Fade()
// Animation when exiting the screen is not via fragmentManager.popBackStack()
// For example, via replace()
// If not specified, will be used
enterTransition returnTransition = Fade()
// Animation when returning to the screen via
fragmentManager.popBackStack()
// If not specified, will be used
enterTransition reenterTransition = Fade()
}
Это еще не главные функции анимации в Fragment API. Следующим этапом разработки являются общие переходы элементов, с помощью которых можно получить реализацию перехода.
Для создания такой анимации мы будем использовать метод FragmentTransaction.addSharedElement(View, String)
и стандартный переход ChangeBounds().
Во-первых, нам нужно сделать элементы представления, которые мы хотим анимировать, уникальными в пределах разметки transitionName
. Это можно сделать через xml или в коде. В InnerFragment
мы указываем анимации:
<!--- fragment_outer_layout.xml -->
<TextView
android:id="@+id/textViewStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Outer Fragment"
android:transitionName="text_start" />
<!--- fragment_inner_layout.xml -->
<TextView
android:id="@+id/textViewDestination"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Inner Fragment"
android:transitionName="text_destination" />
// OuterFragment.kt
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
ViewCompat.setTransitionName(imageViewStart, "image_start")
}
// InnerFragment.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Animation when opening a fragment
sharedElementEnterTransition = ChangeBounds()
// Animations when closing a fragment
// If not specified, sharedElementEnterTransition will be used
sharedElementReturnTransition = ChangeBounds()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
ViewCompat.setTransitionName(imageViewDestination, "image_destination")
}
Вызываем транзакцию:
// OuterFragment.kt
parentFragmentManager.commit {
setReorderingAllowed(true)
addSharedElement(imageViewStart, "image_destination")
addSharedElement(textViewStart, "text_destination")
replace<InnerFragment>(R.id.container)
addToBackStack(null)
}
Если все представления отрисовываются синхронно, мы можем получить показанную выше анимацию точно так же.
Если мы используем переход общего элемента с RecyclerView, нам нужно помнить, что он отрисовывает свои элементы после того, как отрисовывается макет экрана. Получается, что анимацию перехода нужно приостановить, пока список элементов не будет готов к отрисовке.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// Pausing the transition
postponeEnterTransition()
// Waiting for everything to load
viewModel.data.observe(viewLifecycleOwner) {
// Passing data to RecyclerView adapter
adapter.setData(it)
// We are waiting for all the elements to be ready for drawing, and start
// the animation
(view.parent as? ViewGroup)?.doOnPreDraw {
startPostponedEnterTransition()
}
}
}
Метод delayEnterTransition() требует использования FragmentTransaction.setReorderingAllowed(true).
Я также прикреплю ссылку на официальную документацию от Google по анимации фрагментов здесь.
Оригинал