Анимировать переход между фрагментами

284

Я пытаюсь оживить переход между фрагментами. Я получил ответ от следующих
фрагментов Android и анимации

FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right);

DetailsFragment newFragment = DetailsFragment.newInstance();

ft.replace(R.id.details_fragment_container, newFragment, "detailFragment");

// Start the animated transition.
ft.commit();

И мой R.anim.slide_in_left

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
        <translate android:fromXDelta="50%p" android:toXDelta="0"
            android:duration="@android:integer/config_mediumAnimTime"/>
       <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
            android:duration="@android:integer/config_mediumAnimTime" />
</set>

Но когда я попробовал это, это показало

02-08 16:27:37.961: ERROR/AndroidRuntime(1717): FATAL EXCEPTION: main
02-08 16:27:37.961: ERROR/AndroidRuntime(1717): java.lang.RuntimeException: Unknown animator name: translate
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.animation.AnimatorInflater.createAnimatorFromXml(AnimatorInflater.java:129)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.animation.AnimatorInflater.createAnimatorFromXml(AnimatorInflater.java:126)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.animation.AnimatorInflater.createAnimatorFromXml(AnimatorInflater.java:93)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.animation.AnimatorInflater.loadAnimator(AnimatorInflater.java:72)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.FragmentManagerImpl.loadAnimator(FragmentManager.java:621)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:733)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:919)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.BackStackRecord.run(BackStackRecord.java:578)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1217)

Любые идеи? Когда я проверил Honeycomb API, ссылка translateесть. Что я пропустил?
Есть ли другой способ оживить переход между фрагментами? Спасибо

Лабиб Панампуллан
источник
использовать аниматор --- не анимация! использовать android.R.ANIMATOR.fade_in работает, не использовать android.R.ANIM.fade_in - имеет
ошибки

Ответы:

348

Вам нужно использовать новый android.animationкаркас (объектные аниматоры) с FragmentTransaction.setCustomAnimationsа также FragmentTransaction.setTransition.

Вот пример использования setCustomAnimationsиз FragmentHideShow.java из ApiDemos :

ft.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out);

и вот соответствующий аниматор XML из res / animator / fade_in.xml :

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:interpolator/accelerate_quad"
    android:valueFrom="0"
    android:valueTo="1"
    android:propertyName="alpha"
    android:duration="@android:integer/config_mediumAnimTime" />

Обратите внимание, что вы можете комбинировать несколько аниматоров, используя <set>обычную анимационную среду.


РЕДАКТИРОВАТЬ : Поскольку люди спрашивают о слайд-ин / слайд-аут, я прокомментирую это здесь.

Выдвижной и выдвижной

Вы , конечно , можете анимировать translationX, translationY, xи yсвойства, но , как правило слайды включают анимацию содержимого с вне экрана. Насколько я знаю, нет никаких свойств перехода, которые используют относительные значения. Однако это не мешает вам писать их самостоятельно. Помните, что для анимации свойств просто требуются методы getter и setter для объектов, которые вы анимируете (в данном случае представлений), поэтому вы можете просто создать свои собственные методы getXFractionи setXFractionметоды в подклассе представления, например так:

public class MyFrameLayout extends FrameLayout {
    ...
    public float getXFraction() {
        return getX() / getWidth(); // TODO: guard divide-by-zero
    }

    public void setXFraction(float xFraction) {
        // TODO: cache width
        final int width = getWidth();
        setX((width > 0) ? (xFraction * width) : -9999);
    }
    ...
}

Теперь вы можете анимировать свойство 'xFraction', например так:

res / animator / slide_in.xml :

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/linear_interpolator"
    android:valueFrom="-1.0"
    android:valueTo="0"
    android:propertyName="xFraction"
    android:duration="@android:integer/config_mediumAnimTime" />

Обратите внимание, что если объект, в котором вы анимируете, не такой же ширины, как его родительский объект, все будет выглядеть не совсем правильно, поэтому вам может потребоваться настроить реализацию свойства в соответствии с вашим вариантом использования.

Роман Нурик
источник
8
Я получил fade_in и fade_out на работу, но другие в / res / animator выдают ошибки. И ни один из них, похоже, не для скольжения и выскальзывания. Я пытался написать свои собственные XML, чтобы сделать это, но все, что я заканчиваю, это фрагменты поверх фрагментов. Еще помощь, пожалуйста?
Дэйв Маклин
А как насчет перевода? Как вы делаете перевод со значениями в процентах в objectAnimator определить в XML, пожалуйста? Мне не удалось анимировать AdapterViewFlipper во время перелистывания с анимацией вертикального слайда, определенной в xml ...
GBouerat
6
Я получаю 11-19 10: 27: 50.912: W / PropertyValuesHolder (23107): Метод setXFraction () с типом float не найден в целевом классе android.widget.FrameLayout. Но в моем XML у меня есть свой собственный вид MyFrameLayout. Любые идеи?
Барксайд
13
На самом деле, Роман, совет должен идти и другим путем: при использовании библиотеки поддержки вам нужно использовать старый фреймворк анимации (android.R.anim) с FragmentTransaction.setCustomAnimations ao
pjv
1
@RomanNurik этот ответ отлично работал на большинстве устройств, но для некоторых пользователей (особенно на некоторых телефонах Samsung Galaxy S3 / 4) по какой-то причине во время анимации не сообщалось о ширине, из-за чего фрагмент никогда не появлялся. Я смог заставить его работать для тех пользователей, использующих OnPredrawListener, как показано здесь: mavyasoni9891.blogspot.com/2014/06/…
ajpolt
188

Я сделал так:

Добавьте этот метод для замены фрагментов с анимацией :

public void replaceFragmentWithAnimation(android.support.v4.app.Fragment fragment, String tag){
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    transaction.setCustomAnimations(R.anim.enter_from_left, R.anim.exit_to_right, R.anim.enter_from_right, R.anim.exit_to_left);
    transaction.replace(R.id.fragment_container, fragment);
    transaction.addToBackStack(tag);
    transaction.commit();
}

Вы должны добавить четыре анимации в папку anim, которая связана с ресурсом :

enter_from_left.xml :

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:fromXDelta="-100%" android:toXDelta="0%"
        android:fromYDelta="0%" android:toYDelta="0%"
        android:duration="700"/>
</set>

exit_to_right.xml :

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:fromXDelta="0%" android:toXDelta="100%"
        android:fromYDelta="0%" android:toYDelta="0%"
        android:duration="700" />
</set>

enter_from_right.xml :

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:fromXDelta="100%" android:toXDelta="0%"
        android:fromYDelta="0%" android:toYDelta="0%"
        android:duration="700" />
</set>

exit_to_left.xml :

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:fromXDelta="0%" android:toXDelta="-100%"
        android:fromYDelta="0%" android:toYDelta="0%"
        android:duration="700"/>
</set>

Вывод:

введите описание изображения здесь

Его Готово .

Хирен Патель
источник
14
Отличное решение. Однако я не уверен, почему вы обменялись указаниями к RTL. Мой метод:.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right)
Зед
2
Отличное решение. Аналогичный подход и одинаковые файлы анимации работают для переходов между действиями.
Стэн
1
@MikeZriel, res -> anim -> разместите свой xml здесь
Hiren Patel
3
Спасибо Хирен, я изменяю скорость (700) на (300) гораздо лучше и больше как iOS
Майк Зриэль
3
LOL, я вернулся с решением. Я импортировал android.app.fragment и FragmentManager для каждого класса Java. После проверки некоторых материалов я обнаружил, что для использования функции setCustomAnimations () необходимо импортировать библиотеку android.support.v4. важно сказать, что должно быть 'support.v4.app'! Я заменил все методы «getFragmentManager ()» на «getSupportFragmentManager ()» и все импортные «android.app.Fragment / FragmentManager ...» в «android.support.v4.app ....», а затем анимация начала работать без сбоев ... Если вы, ребята, застряли в подобных случаях, прочитайте мое решение.
Спасибо Хирен
58

Если вы можете позволить себе привязать себя только к Lollipop и позже, это, кажется, делает свое дело:

import android.transition.Slide;
import android.util.Log;
import android.view.Gravity;
.
.
.
f = new MyFragment();
f.setEnterTransition(new Slide(Gravity.RIGHT));
f.setExitTransition(new Slide(Gravity.LEFT));
getFragmentManager()
    .beginTransaction()
    .replace(R.id.content, f, FRAG_TAG)  // FRAG_TAG is the tag for your fragment
    .commit();

Надеюсь это поможет.

scorpiodawg
источник
1
Хотя это будет достигнуто в Lollipop, это вряд ли практично, так как процент устройств, на которых запущен Lollipop, незначителен (в настоящее время 1,6% устройств Android используют Lollipop).
Эран Голдин
1
new Slide(...): вызов требует API уровня 21
Chintan Soni
что означает getKey ()?
Альваро
13
@EranGoldin Ничто не длится вечно ... не могли бы вы сегодня посмеяться над решением Android 2.0+?
Том
@ У тебя есть смысл. Однако, когда ваше приложение имеет большую пользовательскую базу, вы не можете просто поднять уровень API. Если большинство ваших пользователей больше не смогут запускать ваше приложение после этого, это совсем не решение.
Эран Голдин
47

Ответ Нурика был очень полезным, но я не мог заставить его работать, пока не нашел это . Короче говоря, если вы используете библиотеку совместимости (например, SupportFragmentManager вместо FragmentManager), синтаксис файлов анимации XML будет другим.

strangeluck
источник
28

Вот анимация слайдов между фрагментами:

FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setCustomAnimations(R.animator.enter_anim, R.animator.exit_anim);
transaction.replace(R.id.listFragment, new YourFragment());
transaction.commit();

Мы используем объектAnimator.

Вот два XML-файла в подпапке аниматора .

enter_anim.xml

<?xml version="1.0" encoding="utf-8"?>
<set>
     <objectAnimator
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:duration="1000"
         android:propertyName="x"
         android:valueFrom="2000"
         android:valueTo="0"
         android:valueType="floatType" />
</set>

exit_anim.xml

<?xml version="1.0" encoding="utf-8"?>
<set>
    <objectAnimator
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="1000"
        android:propertyName="x"
        android:valueFrom="0"
        android:valueTo="-2000"
        android:valueType="floatType" />
</set>

Я надеюсь, что это поможет кому-то.

kirilv
источник
37
перемещение изображения на 2000 пикселей - очень уродливое решение.
carlo.marinangeli
4
Для меня exit_anim просто «вылетает» с экрана, он не оживляет экран. Любые идеи? Я использую.setCustomAnimations(R.animator.slide_in_left, R.animator.slide_out_right, R.animator.slide_in_left, R.animator.slide_out_right)
г-н Пабло
@MrPablo, причина, вероятно, в том, что вы не скопировали вставленный код выше. setCustomAnimations должен быть вызван перед методом замены.
Галя
В этом случае, если я заменяю другой фрагмент анимацией и минимизирую приложение непосредственно перед тем, как время ожидания анимации или длительность снова и снова возвращаются в приложение, оно отобразит предыдущий фрагмент и текущий фрагмент параллельно.
Принц
23

Для всех, кого поймают, убедитесь, что setCustomAnimations вызывается перед вызовом для замены / добавления при построении транзакции.

Чарли
источник
12

Реализация FragmentTransaction в Android SDK требует Animatorподдержки библиотеки Animation, не спрашивайте меня, почему, но после комментария странного лука я изучил код Android 4.0.3 и библиотеку поддержки. Android SDK использует loadAnimator()и поддерживает использование библиотекиloadAnimation()

sherpya
источник
7

Попробуйте использовать это простое и быстрое решение. Android предоставляет некоторые значения по умолчанию animation.

fragmentTransaction.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right);

FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right);
fragmentManager.addOnBackStackChangedListener(this);
fragmentTransaction.replace(R.id.frame, firstFragment, "h");
fragmentTransaction.addToBackStack("h");
fragmentTransaction.commit();

Вывод:

введите описание изображения здесь

Gowthaman M
источник
Вау .. это должен быть принятый ответ !! Простое и элегантное решение. Это очень гладко по сравнению с другими предлагает ответы
Чатура Буддика