Анімуйте перехід між фрагментами


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)

Будь-які ідеї? Коли я перевірив, посилання API Honeycomb API translateє. Що я пропустив?
Чи є якийсь інший спосіб оживити перехід між фрагментами? Дякую


використовувати ANIMATOR --- не анімацію! використовуйте android.R.ANIMATOR.fade_in працює, НЕ використовуйте android.R.ANIM.fade_in - він має поведінку BUGS
user1269737

Відповіді:


347

Вам потрібно використовувати новий android.animationфреймворк (аніматори об'єктів) з FragmentTransaction.setCustomAnimations, а також FragmentTransaction.setTransition.

Ось приклад використання setCustomAnimationsіз фрагмента ApiDemos ' FragmentHideShow.java :

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властивості, але , як правило слайди включають анімацію вмісту з поза екраном. Наскільки я знаю, немає перехідних властивостей, які використовують відносні значення. Однак це не заважає писати їх самі. Пам’ятайте, що для анімації властивостей просто потрібні методи отримання та налаштування об’єктів, якими ви анімуєте (у цьому випадку перегляди), тож ви можете просто створити свої власні 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();
}

Ви повинні додати чотири анімації в папку аніма, яка асоціюється з ресурсом :

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)
zed

2
Дивовижне рішення. Аналогічний підхід і ті ж файли анімації працюють для переходів між видами діяльності.
Стен

1
@MikeZriel, res -> anim -> покладіть сюди свій xml
Hiren Patel

3
Дякую Хірен, я
змінюю

3
LOL, я повернувся з рішенням. Я імпортував android.app.fragment та FragmentManager для кожного класу java. Перевіривши деякі матеріали, я виявив, що для використання "setCustomAnimations ()" потрібно імпортувати бібліотеку android.support.v4. важливо сказати, що це має бути "support.v4.app"! Я замінив усі методи 'getFragmentManager ()' на 'getSupportFragmentManager ()', а весь імпорт 'android.app.Fragment / FragmentManager ...' на 'android.support.v4.app ....', потім це анімація почала добре працювати без збоїв ... Якщо ви, хлопці, застрягли в подібних випадках, прочитайте моє рішення. Thx Hiren Patel xD
KoreanXcodeWorker

58

Якщо ви можете дозволити собі прив’язати себе просто до льодяника і пізніше, це, здається, зробить трюк:

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();

Сподіваюсь, це допомагає.


1
Незважаючи на те, що це вдасться досягти на Lollipop, навряд чи практично, оскільки відсоток пристроїв, на яких працює Lollipop, незначний (на даний момент 1,6% пристроїв Android працює на Lollipop).
Еран Голдін

1
new Slide(...): для виклику потрібен рівень 21
Чінтан Соні

що означає getKey ()?
Альваро

13
@EranGoldin Ніщо не триває вічно. Чи б ви сьогодні знущалися над рішенням для Android 2.0+?
Том

@Тому у вас є пункт. Однак, коли у вашої програми є велика база користувачів, ви не можете просто збільшити рівень API. Якщо більшість ваших користувачів після цього більше не зможе запустити додаток, це зовсім не рішення.
Еран Голдін

47

Відповідь Нуріка була дуже корисною, але я не зміг змусити її працювати, поки не знайшов цього . Якщо коротко, якщо ви використовуєте бібліотеку сумісності (наприклад, SupportFragmentManager замість FragmentManager), синтаксис файлів анімації XML буде іншим.


28

Ось анімація про слайд введення / виводу між фрагментами:

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

Ми використовуємо objectAnimator.

Ось два 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>

Я сподіваюся, що це комусь допоможе.


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

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


7

Спробуйте скористатися цим простим і швидким рішенням. Android надає деякі за замовчуванням animations.

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();

Вихід:

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


Вуо .. це повинна бути прийнята відповідь !! Просте і елегантне рішення. Це дуже гладко в порівнянні з іншими
підказами
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.