- Анимация фрагментов
- fragment1.xml
- fragment2.xml
- Fragment1.java
- slide_in_left.xml
- slide_in_right.xml
- Переворачиваем карту
- card_flip_left_enter.xml
- card_flip_left_exit.xml
- card_flip_right_enter.xml
- card_flip_right_exit.xml
- fragment_card_front.xml
- fragment_card_back.xml
- Fragment Transitions
- Getting them working
- Postpone
- Reordering
- Waiting for your parent
- Анимация переходов между двумя фрагментами
- Поддержка предыдущих версий Android?
- Имена переходов
- Настройка FragmentTransaction
- Настройка анимации перехода
- Классы анимации перехода
- Все вместе
- Анимации c помощью Transitions API
- Простые типы Transition
- Сцены
- И о главном. Бэкпорт
- О библиотеке
- Что нового в API из 5.0
- Targets
- Задаем Transition через xml
- Кастомные Transitions
Анимация фрагментов
Android позволяет переключаться между фрагментами с помощью анимационных эффектов. Рассмотрим примеры с применением готовых эффектов, а также создадим свою собственную анимацию.
Создадим новый проект с главной активностью. В активность динамически будут подключаться фрагменты, между которыми будем переключаться с анимационными эффектами при помощи кнопки. Компонент FrameLayout послужит контейнером для подключаемых фрагментов.
Разметка для активности:
Создадим разметки для фрагментов.
fragment1.xml
fragment2.xml
Отличия между фрагментами — фоновый цвет (красный и зелёный) и текст, по которым будет проще различать фрагменты.
Фрагмент должен иметь свой класс. Для примера достаточно простейшего кода, где нужно указать разметку фрагмента.
Fragment1.java
По такому же принципу создайте класс для второго фрагмента самостоятельно.
Теперь перейдём к коду для главной активности:
В коде я закомментировал две строчки для анимации. В таком виде переключение между фрагментами происходит стандартным способом без анимации. Теперь раскомментируйте первую строчку transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);. В классе FragmentTransaction есть несколько готовых анимаций. С помощью метода setTransition(int transit) мы можем указать нужную анимацию и увидеть её в действии.
- TRANSIT_FRAGMENT_CLOSE
- TRANSIT_FRAGMENT_OPEN
- TRANSIT_FRAGMENT_FADE
- TRANSIT_NONE
Снова закомментируйте строку и раскомментируйте вторую строку transaction.setCustomAnimations(R.animator.slide_in_left, R.animator.slide_in_right);. Метод setCustomAnimations() позволяет указать собственную анимацию. Методу передаются два параметра. Первый параметр описывает анимацию для фрагмента, который появляется, а второй — описывает анимацию для фрагмента, который убирается с экрана устройства. Метод следует вызывать до появления фрагментов, иначе анимация не будет применена.
С методом setCustomAnimations() нужно быть осторожным при работе с фрагментами из support-библиотеки. В одной из версий библиотеки разработчики из Гугла всё поломали и код перестал работать. Неизвестно когда починят. Поэтому используйте стандартные фрагменты.
Для анимации нужно создать XML-файлы в папке res/animator (её тоже нужно создать вручную).
slide_in_left.xml
slide_in_right.xml
Элементы визуальных эффектов задаются в теге objectAnimator. У атрибута propertyName указывается свойство фрагмента, которое мы будем изменять при анимации, valueType указывает тип изменяемого параметра. Атрибуты valueFrom и valueTo указывают диапазон изменения параметра, указанного в propertyName. Если параметр valueFrom не указан, то значение берётся равное текущему. В нашем случае valueFrom равен -1280, это означает, что движение фрагмента по оси y будет начинаться со значения -1280 и перемещение будет происходить пока значение y не станет равным 0 для верхнего левого угла нашего фрагмента в течении 1500 миллисекунд (атрибут duration).
Тег set служит для объединения эффектов либо их разделения. В файле slide_in_right.xml используется атрибут ordering со значением together, что означает проигрывать эффекты одновременно, в противовес ему существует значение sequentially, которое требует последовательного отображения эффектов в анимации.
Переворачиваем карту
Напишем ещё один пример для закрепления материала.
Найдите в интернете две картинки, например, изображения карты и её рубашки. Подготовим четыре файла в папке res/animator.
card_flip_left_enter.xml
card_flip_left_exit.xml
card_flip_right_enter.xml
card_flip_right_exit.xml
В файле res/values/strings.xml добавьте пару новых ресурсов.
Теперь создадим два макета для двух фрагментов в папке res/layout. Фрагменты будут содержать по одной картинке.
fragment_card_front.xml
fragment_card_back.xml
Создаём два класса для фрагментов, которые загружают свои макеты.
Упростим макет активности.
Осталось написать код. Ещё раз напомню, что используйте стандартные фрагменты, а не из библиотеки совместимости.
Контейнер обрабатывает касание пальца как щелчок и переворачивает фрагмент на другой. Результат в видео.
Источник
Fragment Transitions
Getting them working
This is the first post in a small post series where I explore how to get transitions working nicely with fragments. This post is all about getting them running.
A couple of months ago I showed a grid to grid transition from an app I’m building called Tivi.
Before I managed to get to that point though, I was stuck on getting any transition to work. In the app I’m using fragment changes for non-boundary changes, so things like expanding data sets and bottom navigation events. When the type of data significantly changes (for instance, drilling down into the details of a single item) I start an activity.
The change you’re seeing above is a fragment replacement. Fragment A is the overview screen, and then when the user clicks on the ‘More’ button, it is replaced with Fragment B which contains the full grid of items.
My existing fragment transaction code looked like this:
Nothing exciting yet.
So I looked up the transition APIs and added some shared elements. In this case the shared elements were the square images containing posters:
And then I set a shared element transition on the entering fragment (Fragment B). In this case I used a ChangedBounds to get started since the views were just moving from point A ➡️ B and changing size.
At this point I optimistically expected it to just work, but I actually got this:
So it did not work at all on the enter, but worked fine on the return transition. It’s a start.
Postpone
At this point I remembered something which my colleague, Nick Butcher, had mentioned to me in the past while he was writing transitions for Plaid. Specifically around having to postpone transitions until your views are ready (laid out, data loaded, etc).
So off I went and added postponing and starting to my fragments:
We have to do this for both the entering and exiting fragments so that both the enter (click) and the exit (back button) work as expected.
But still no enter transition. 🤦
Reordering
I cheated a bit here and reached out to Mr Activity-Fragment-Transitions, George Mount, from the Android team. He pointed out what I needed to do to get it working: reordering.
It turns out that you have to enable reordering fragment transactions for postponed fragment transitions to work. Luckily this is pretty simple to do (but easily forgotten):
After that the enter transition occasionally worked, but most of the time I just got a crossfade. At least the transitions were running some of the time now though.
Waiting for your parent
Spurred on with the fact that my transition was at least running sometimes, I started debugging. I deduced that the times which the transition did run, the views had been laid out ( isLaidOut == true ) and drawn already.
So the final piece of the puzzle here was… waiting.
If you look back at our postpone calls, we’re actually starting the postponed transition as soon as the data has loaded. We need to give the views a chance to be updated, laid out, and more importantly, drawn before we start the transition.
So our new postpone calls become:
You may wonder why we set the OnPreDrawListener on the parent rather than the view itself. Well that is because your view may not actually be drawn, therefore the listener would never fire and the transaction would sit there postponed forever. To work around that we set the listener on the parent instead, which will (probably) be drawn.
And voilà, we have a working transition:
You might be wondering why this does not look like the tweet I included above. I’ll cover that in a later post. ✨⚡. The next post will look at getting window insets working with fragment transitions.
If you’re wondering where the doOnPreDraw method has come from, it is from android-ktx. If you’re using Kotlin in your app, make sure to check it out.
Источник
Анимация переходов между двумя фрагментами
Одним из краеугольных камней в Material design являются осмысленные движения между экранами. Lollipop предоставляет поддержку этих анимаций в форме фреймворка переходов между Activity и Fragment. Поскольку статей по данной теме не так много, я решил написать свою собственную!
Наш конечный продукт будет достаточно прост. Мы будем делать приложение-галерею с котиками. При нажатии на изображение будет открываться экран с подробностями. Благодаря фреймворку переход из сетки изображений в окно с подробностями будет сопровождаться анимацией.
Если вы желаете увидеть, что получилось — готовое приложение находится на GitHub.
Поддержка предыдущих версий Android?
У меня есть для вас две новости: хорошая и плохая. Плохая новость заключается в том, что до Lollipop данный фреймворк не работает. Не смотря на это, проблема решается методами библиотеки поддержки с помощью которой вы можете реализовать анимированые переходы доступные в API 21+.
В статье будут использоваться функции из библиотеки поддержки для обеспечения перемещения контента.
Имена переходов
Для ассоциации View на первом экране и его двойника на втором нужна связь. Lollipop предлагает использовать свойство “transition name” для связи View между собой.
Существует два способа добавления имени перехода (transition name) для ваших View:
- В коде можно использовать ViewCompat.setTransitionName() . Конечно, вы так же можете просто вызвать setTransitionName() , если поддержка начинается с Lollipop.
- Для добавления в XML, используйте атрибут android:transitionName .
Важно отметить, что внутри одного макета (layout), имена переходов должны быть уникальны. Держите это в уме при организации переходов. Указывая transition name для ListView или RecyclerView задаст это же имя и для всех остальных элементов.
Настройка FragmentTransaction
Настройка FragmentTransactions должна быть вам очень знакомой:
Чтобы указать какую View будем передавать между фрагментами — используем метод addSharedElement() .
Переданная View в addSharedElement() это View из первого фрагмента, которую вы хотите разделить (share) со вторым фрагментом. Имя перехода тут является именем перехода в разделенной (shared) View во втором фрагменте.
Настройка анимации перехода
Наконец-то пришел момент, когда мы зададим анимацию перехода между фрагментами.
Для shared элементов:
- Для перехода с первого фрагмента во второй используем метод setSharedElementEnterTransition() .
- Для возврата назад используем метод setSharedElementReturnTransition() . Анимация произойдет при нажатии кнопки назад.
Заметьте, что вам необходимо вызвать эти методы во втором фрагменте, поскольку, если вы сделаете это в первом — ничего не произойдет.
Вы так же можете анимировать переходы для всех non-shared View. Для этих View, используйте setEnterTransition() , setExitTransition() , setReturnTransition() , и setReenterTransition() в соответствующих фрагментах.
Каждый из этих методов принимает один параметр Transition предназначенный для выполнения анимации.
Создавать анимацию мы будем очень просто. Мы используем наш кастомный transition для передвижения изображения (об этом чуть позже), и исчезание ( Fade ) при выходе.
Классы анимации перехода
Android предоставляет некоторые готовые анимации переходов, что подходят для большинства случаев. Fade выполняет анимацию исчезновения. Slide анимирует переход появления/исчезновения скольжением из угла экрана. Explode анимация подобная взрыву, изображение движется от краев экрана. И наконец, AutoTransition заставит изображение исчезать, двигаться и изменять размер. Это лишь некоторые примеры из пакета перемещений, их на самом деле намного больше!
Я упоминал, что нам понадобится кастомный переход для нашего изображения. Вот он:
Наш кастомный переход есть ни что иное как набор из трех готовых переходов собранных вместе:
- ChangeBounds
анимирует границы (положение и размер) нашей view. - ChangeTransform
анимирует масштаб view, включая родителя. - ChangeImageTransform
позволяет нам изменять размер (и/или тип масштаба) нашего изображения
Если вам интересно узнать, как они втроем взаимодействуют попробуйте поиграть с приложением, поочередно убирая то одну то другую анимации, наблюдая за тем как все ломается.
Вы так же можете создать более сложные анимации используя XML. Если вы предпочитаете XML, то вам будет интересно посмотреть документацию на сайте андроида Transition
.
Все вместе
Код который в итоге у нас получился оказался достаточно простым:
Вот и все! Простой способ реализации анимации переходов между двумя фрагментами готов!
Источник
Анимации c помощью Transitions API
На хабре ещё не была освещена тема Transitions API для анимаций, которые появились в Android начиная с 4.4 (KitKat) и продолжили свое развитие в 5.0 (Lollipop). В своей статье я расскажу о том, как упростить работу с анимациями с их использованием и как применять их на любом устройстве с версией Android 4.0 и выше.
Вместе с Android 4.4 был представлен новый механизм анимации изменений в layout. Ещё в версии 4.0 появился первый вариант решения этой проблемы — флаг animateLayoutChange для ViewGroup. Но даже с вызовом метода getLayoutTransition() и изменением его параметров он был недостаточно гибок и не давал полного контроля над тем, как будет анимироваться наше изменение (transition).
KitKat Transition API приносит нам понятия сцены — Scene и некоторого изменения между сценами — Transition. В добавок к ним вводим понятие Scene root для определения корневого layout, внутри которого будут происходить изменения сцен. А сама сцена это некоторый враппер над ViewGroup, который описывает конкретное состояние его самого и всех содержащихся в нем объектов View.
Теперь про сам Transition. Это механизм, отвечающий за считывание требуемых значений параметров у View, которые изменились при смене сцен и генерирующий анимации для плавного изменения этих состояний.
Начнем с самого простого варианта использования Transitions API.
Представим, что текущее состояние нашего layout это первая сцена. Допустим у нас просто изображен квадрат.
Опишем layout через xml:
Теперь мы просто хотим анимированно увеличить размер нашего квадрата. Чтобы уже начать привыкать к понятию сцен назовем это изменение переходом ко второй сцене.
Результат:
Неплохо, анимация всего одной строкой. Причем таких изменений внутри layout может быть любое количество.
Теперь попробуем настроить некоторые параметры анимации. Для этого нужно указать конкретный Transition, который мы будем выполнять. Метод beginDelayedTransition может принимать вторым параметром любого наследника класса Transition. Именно про них мы сейчас и поговорим.
Простые типы Transition
Сцены
Вернемся к сценам. В первом примере мы разобрали самый простой способ использования API. Но сцены можно описывать и более формально, например, чтобы было удобнее между ними переключаться.
Опишем layout нашего Activity так, чтобы в нем была кнопка для смены сцен и FrameLayout, который будет нашим Scene root. Внутрь его сразу ставим layout, который является первой сценой, но вынесем его в отдельный файл.
Содержимое scene1. Поместим туда всё тот же квадрат, но в левый верхний угол:
И создадим файл scene2. Квадрат переместим в правый верхний угол и увеличим в размерах. Также, добавим TextView, которого не было в первой сцене.
В onCreate у Activity опишем:
Результат:
И о главном. Бэкпорт
Легко понять, почему этим API ещё мало кто пользуется и даже мало кто про него знает. Сейчас то время, когда разработчики только недавно осознали моральное право отказаться от поддержки Android 2.x и большинство новых проектов наконец начинаются с поддержкой minSdk Android 4.0. Но пока ещё мало смысла использовать API, которое будет работать только начиная с 4.4, ведь большинство девайсов ещё на более старых версиях.
Но! Transition API уже можно использовать для Android 4.0+ и везде анимация будет работать одинаково. Для этого я разрабатываю библиотеку, которую назвал Transitions Everywhere. Она является бэкпортом Transition API на более старые версии Android. Для интеграции в свой проект требуется подключить библиотеку как gradle зависимость:
И для всех классов, связанных с этим API, заменить импорт на пакет com.transitionseverywhere.* вместо android.transition.*
О библиотеке
Когда я начал интересоваться этой темой я нашел две похожие библиотеки:
github.com/guerwan/TransitionsBackport
github.com/pardom/TransitionSupportLibrary
Что их объединяет, так это то, что их создатели, видимо, забили на их развитие и обе они не реализовали до конца все, что можно было бы реализовать для обратной совместимости некоторых функциональностей на старых версиях Android. Я взял их за основу и добавил много нового. Различные исправления некоторых некорректных поведений, которые проявлялись, например на версиях до 4.3. К тому же, API моей библиотеки совместимо с версиями Android 2.2+, но на версиях до 4.0 смена сцен(layout) будет выполняться без анимации. Также, я стараюсь идти в ногу со временем. Не так давно выпустили новую версию Android 5.0 (Lollipop) и код всего пакета transitions API в ней, также, во многом изменился. Я смержил все изменения в свою библиотеку.
Что нового в API из 5.0
- Появилась возможность задавать TransitionName для View. Помечая одним и тем же именем View в первой и во второй сцене мы говорим, что переход именно между ними нужно анимировать. Это удобно, потому что раньше нам необходимо было для двух сцен, описанных в разных xml файлах указывать одинаковые id для таких View. В 5.0 transitionName можно указывать как атрибут в описании через xml, или вызывая метод setTransitionName у любого наследника View. В своей библиотеке я эту функциональность частично портировал таким образом: я предлагаю вызывать статический метод TransitionManager.setTransitionName(View v, String transitionName) вместо аналогичного у самого наследника View и отказаться от установки transitionName через xml.
- Explode. Во многом похож на Slide, но View будет выбегать или из некоторого направления, который задается с помощью так называемого эпицентра Transition(см. метод setEpicenterCallback) или же из случайного угла, если этот эпицентр не задан.
- TransitionPropagation. Описывает задержку начала анимации. Например, при установке CircularPropagation чем View ближе к установленному эпицентру, тем раньше она начинает анимироваться. Задается для Transition через параметр setPropagation.
Пример удаления всех View из FrameLayout с Explode Transition и установленным CircularPropagation(эпицентром ставится точка тапа на экран):ChangeImageTransform. Transition, который анимирует матричный переход изображения внутри ImageView. С помощью него можно плавно изменять размеры и scaleType изображений. Разберем на примере. Барышню слева мы подвергли операциям ChangeBounds и ChangeImageTransform, тогда как девушке справа достался только ChangeBounds. Невооруженным взглядом заметно как правая «дергается» в начале анимации:
- ChangeClipBounds. Плавное изменение параметра clipBounds у View. Но! Так как метод setClipBounds появился только в Android 4.3, то и изменять этот параметр и его же анимировать мы сможем только начиная с этой версии. Пример:
- Path (Curved) motion. Появилась возможность устанавливать для любого Transition правило расчета координат параметров, состоящих из двух координат с помощью метода setPathMotion. например, при изменении координат x и y, View может прибежать к новым координатам не по прямой, а по дуге. Чтобы показать пример того, как это выглядит просто приведу ссылку на неплохую статью об этом.
- Немного о том, что ещё появилось нового, но что пока не удалось портировать.
Activity Transition, хорошо разрекламированный гуглом в анонсах Lollipop и Material Design. Видимо, много логики спрятано в самих Activity, даже нужно устанавливать специальный флаг. Так что, напрямую это портировать не так просто. Та же ситуация и с Fragment Transition.
Новый Transition под именем ChangeTransform — аналог ChangeImageTransform, но применяет матричное преобразование для любых View.
Targets
Задаем Transition через xml
Сами Transition можно загружать из xml файла. Его кладем в папку res/anim. Пример
Мы создали набор операций TransitionSet, состоящий из трех других Transition. Заодно применили тут ранее не рассмотренное свойство startDelay — время задержки перед началом выполнения анимации. Аналог для вызова из кода — Transition.setStartDelay(long startDelay).
Можно загружать из xml файла целый TransitionManager, в котором описывать разные правила для смен сцен в зависимости от того, в каком порядке они происходят. Простой пример:
Примечание
Два рассмотренных выше примера подправлены для работы с моей библиотекой Transitions Everywhere. Если использовать системные Transition API, то сами xml файлы нужно класть в директорию res/transition и для всех атрибутов необходимо использовать namespace android: вместо app:
Кастомные Transitions
Чтобы ещё больше убедиться какая крутая штука эти Transitions, давайте напишем свой собственный Transition.
Допустим, мы хотим анимировано изменять размер шрифта у TextView. (Как подсказал в комментариях bimeg, этот пример немного оторван от реальности, потому что не стоит анимировать свойства, каждое изменение которых во время анимации вызывает requestLayout())
От нас требуется переопределить методы captureStartValues, captureEndValues и createAnimator. Первые два отвечают за снятие значений необходимых параметров View до и после смены сцен. А метод createAnimator, собственно, создает аниматор для этого изменения параметров.
Результат:
Источник