[Перевод] Анимация переходов между двумя фрагментами
Одним из краеугольных камней в Material design являются осмысленные переходы между экранами. Lollipop предоставляет поддержку этих анимаций в форме фреймворка переходов между Activity и Fragment. Поскольку статей по данной теме не так много, я решил написать свою собственную!
Наш конечный продукт будет достаточно прост. Мы будем делать приложение с сеткой из изображений, и при нажатии на изображение будет открываться экран с подробностями. Благодаря фреймворку переходов изображение из сетки будет в анимации переходить в экран с подробностями.
Если вы желаете увидеть, что получилось — готовое приложение находится на GitHub.
У меня есть для вас хорошая и плохая новости. Плохая новость в том, что до Lollipop данный фреймворк не работает. Не смотря на это, проблема решается методами библиотеки поддержки с помощью которой вы можете реализовать переходы с API 21+ без засорения кода проверками на версию API.
В статье будут использоваться функции из библиотеки поддержки для обеспечения перемещения контента.
В отличии от переходов Activity, вам не нужно прописывать Window.FEATURE_ACTIVITY_TRANSITIONS
чтобы использовать переходы Fragment. Вам так же не нужно Window.FEATURE_CONTENT_TRANSITIONS
.
В самом деле, вам не нужно делать ничего особенного — вы уже должны быть готовы к работе!
Для ассоциации View на первом экране и его двойника на втором нужна связь. Lollipop предлагает к использованию свойство “transition name” для ассоциации View
между собой.
Существует два способа чтобы добавить имя перехода (transition name) для ваших View:
- Для добавления в коде вы можете использовать
ViewCompat.setTransitionName()
. Конечно вы так же можете просто вызватьsetTransitionName()
на устройствах Lollipop и выше. - Для добавления в XML, вы можете использовать атрибут
android:transitionName
.
Важно отметить, что внутри одного макета (layout), имена переходов должны быть уникальны. Держите это в уме при организации переходов с ListView
или RecyclerView
. Определив имя перехода для одного из них — задаст это же имя и для всех остальных.
Настройка FragmentTransactions
должна быть вам очень знакомой:
getSupportFragmentManager()
.beginTransaction()
.addSharedElement(sharedElement, transitionName)
.replace(R.id.container, newFragment)
.addToBackStack(null)
.commit();
Чтобы указать какую View будем передавать между фрагментами — используем метод addSharedElement()
.
Переданная View в addSharedElement()
это View из первого фрагмента, которую вы хотите разделить (share) со вторым фрагментом. Имя перехода тут является именем перехода в разделенной (shared) View во втором фрагменте.
Наконец-то пришел момент, когда мы зададим анимацию перехода между фрагментами.
Для shared
элементов:
- Вызовите метод
setSharedElementEnterTransition()
чтобы настроить анимацию View с первого во второй фрагменты. - Вызовите
setSharedElementReturnTransition()
чтобы настроить анимацию перемещения View из второго фрагмента в первый, когда пользователь нажмет кнопку назад.
Заметьте, что вам необходимо вызвать эти методы во втором фрагменте, поскольку, если вы сделаете это в первом — ничего не произойдет.
Вы так же можете анимировать переходы для всех non-shared View. Для этих View, используйте setEnterTransition()
, setExitTransition()
, setReturnTransition()
, и setReenterTransition()
в соответствующих фрагментах.
Каждый из этих методов принимает один параметр Transition
предназначенный для выполнения анимации.
Создавать анимацию мы будем достаточно просто. Мы будем использовать наш кастомный transition для передвижения изображения (об этом чуть позже), и исчезание (Fade
) при выходе.
Android предоставляет некоторые готовые анимации переходов, что подходят для большинства случаев. Fade
выполняет анимацию исчезновения. Slide
анимирует переход появления/исчезновения скольжением из угла экрана. Explode
анимация подобная взрыву, изображение движется от краев экрана. И наконец, AutoTransition
заставит изображение исчезать, двигаться и изменять размер. Это лишь некоторые примеры из пакета перемещений, их на самом деле намного больше!
Я упоминал, что нам понадобится кастомный переход для нашего изображения. Вот он:
public class DetailsTransition extends TransitionSet {
public DetailsTransition() {
setOrdering(ORDERING_TOGETHER);
addTransition(new ChangeBounds()).
addTransition(new ChangeTransform()).
addTransition(new ChangeImageTransform()));
}
}
Этот переход есть ни что иное как набор из трех переходов собранных вместе:
ChangeBounds
анимирует границы (положение и размер) нашей view.ChangeTransform
анимирует масштаб view, включая родителя.ChangeImageTransform
позволяет нам изменять размер (и/или тип масштаба) нашего изображения
Если вам интересно узнать как они втроем взаимодействуют попробуйте поиграть с приложением, поочередно убирая то одну то другую анимации, наблюдая за тем как все ломается.
Вы так же можете создать более сложные анимации используя XML. Если вы предпочитаете XML, то вам будет интересно посмотреть документацию на сайте андроида Transition
.
Код который в итоге у нас получился оказался достаточно простым:
DetailsFragment details = DetailsFragment.newInstance();
// Note that we need the API version check here because the actual transition classes (e.g. Fade)
// are not in the support library and are only available in API 21+. The methods we are calling on the Fragment
// ARE available in the support library (though they don't do anything on API < 21)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
details.setSharedElementEnterTransition(new DetailsTransition());
details.setEnterTransition(new Fade());
setExitTransition(new Fade());
details.setSharedElementReturnTransition(new DetailsTransition());
}
getActivity().getSupportFragmentManager()
.beginTransaction()
.addSharedElement(holder.image, "sharedImage")
.replace(R.id.container, details)
.addToBackStack(null)
.commit();
Вот и все! Простой способ реализации анимации переходов между двумя фрагментами готов!