Фрагменти та анімація Android


265

Як слід реалізувати такий вид ковзання, який, наприклад, використовує клієнт Honeycomb Gmail?

Ви можете TransactionManagerвпоратися з цим автоматично, додаючи та видаляючи фрагменти, це важко перевірити це через те, що емулятор є слайд-шоу :)

Відповіді:


388

Щоб анімувати перехід між фрагментами або анімувати процес показу або приховування фрагмента, ви використовуєте Fragment Managerдля створення Fragment Transaction.

У межах кожної фрагментальної транзакції ви можете вказати та вимкнути анімації, які будуть використовуватися для показу та приховування відповідно (або обох, коли використовується заміна).

Наступний код показує, як ви замінили б фрагмент, висунувши один фрагмент, а інший пересунувши на його місце.

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

Щоб домогтися того ж, сховавши або показавши фрагмент, який ви просто зателефонували б ft.showабо ft.hide, перейшовши у Фрагмент, який ви хочете відповідно показати або приховати.

Для довідки, для визначення анімації XML буде використано objectAnimatorтег. Приклад slide_in_left може виглядати приблизно так:

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

57
Коли я спробував це, він показав RuntimeException: Невідома назва аніматора: перекласти .
Лабеб Панампуллан

3
Переконайтеся, що анімації, визначені в slide_in_left та right, побудовані за допомогою набору визначень objectAnimator, а не старого визначення анімації.
Reto Meier

7
Це дуже допомогло. Я був на правильному шляху, але просто не потрапив туди. Для інших читачів ви також можете мати андроїд: інтерполятор як атрибут із вказаним улюбленим (наприклад, "@android: interpolator / linear"). За замовчуванням використовується "@android: interpolator / accelerate_decelerate".
Дейв Маклін

6
Я націлюю API рівня 7 за допомогою API сумісності. Чи є спосіб для мене оживити фрагменти?
Джеррод Сміт

5
@JarrodSmith ви можете спробувати використати бібліотеку сумісності на зразок NineOldAndroids, щоб звести API Honeycomb в Eclair.
Містер S

249

Якщо вам не потрібно користуватися бібліотекою підтримки, то подивіться на відповідь Романа .

Але якщо ви хочете використовувати бібліотеку підтримки, вам потрібно використовувати стару рамку анімації, як описано нижче.

Після консультацій з відповідями Рето та сліпого я отримав наступний код роботи.

Фрагменти виглядають ковзаючими праворуч і ковзаючи вліво при натисканні на спину.

FragmentManager fragmentManager = getSupportFragmentManager();

FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.setCustomAnimations(R.anim.enter, R.anim.exit, R.anim.pop_enter, R.anim.pop_exit);

CustomFragment newCustomFragment = CustomFragment.newInstance();
transaction.replace(R.id.fragment_container, newCustomFragment );
transaction.addToBackStack(null);
transaction.commit();

Порядок важливий. Це означає, що ви повинні зателефонувати setCustomAnimations()раніше, replace()або анімація не набере чинності!

Далі ці файли потрібно розмістити у папці res / anim .

enter.xml :

<?xml version="1.0" encoding="utf-8"?>
<set>
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
               android:fromXDelta="100%"
               android:toXDelta="0"
               android:interpolator="@android:anim/decelerate_interpolator"
               android:duration="@android:integer/config_mediumAnimTime"/>
</set>

exit.xml :

<set>
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
               android:fromXDelta="0"
               android:toXDelta="-100%"
               android:interpolator="@android:anim/accelerate_interpolator"
               android:duration="@android:integer/config_mediumAnimTime"/>
</set>

pop_enter.xml :

<set>
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
               android:fromXDelta="-100%"
               android:toXDelta="0"
               android:interpolator="@android:anim/decelerate_interpolator"
               android:duration="@android:integer/config_mediumAnimTime"/>
</set>

pop_exit.xml :

<?xml version="1.0" encoding="utf-8"?>
<set>
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
               android:fromXDelta="0"
               android:toXDelta="100%"
               android:interpolator="@android:anim/accelerate_interpolator"
               android:duration="@android:integer/config_mediumAnimTime"/>
</set>

Тривалість анімації можна змінити на будь-яке значення за замовчуванням, наприклад, @android:integer/config_shortAnimTimeабо будь-яке інше число.

Зауважте, що якщо між замінами фрагментів відбувається зміна конфігурації (наприклад, обертання), дія зворотного погляду не анімується. Це задокументована помилка, яка все ще існує у версії 20 бібліотеки підтримки.


47
Це просто врятувало мене. Зауважте, важливо звернути увагу на замовлення , яке, природно, я пропустив вперше. Це означає, що ви повинні викликати setCustomAnimations () перед тим, як замінити ().
Стівен Кідсон

3
Я намагався реалізувати свої фрагменти. Я написав усе, як ви згадали, але logcat говорить: невідоме ім'я аніматора перекласти Як я можу подолати цю проблему? До речі, я називаю свій фрагмент у Навігаційному
ящику

Чудово працює, але виявляється, що будуючи це за допомогою інструментів збирання 21.1, створюється помилка, яка говорить "Неправильне ім'я файлу: повинно містити лише малі літери та цифри ([a-z0-9_.])". Я пропоную відредагувати назви файлів у відповідях на pop_enter.xml та pop_exit.xml.
smichak

Прекрасне рішення, і воно чудово працює, коли я натискаю кнопку назад. У мене просто одне запитання: Якщо я хочу створити власну backButton, який код я повинен зателефонувати, щоб повторити поведінку з кнопки "назад"?
Томас Тейльман

1
Томас, якщо ти хочеш повернутись, слід застосувати таку форму: .setCustomAnimations (R.anim.pop_enter, R.anim.pop_exit, R.anim.enter, R.anim.exit)
Алекс Зараос

26

Я б радимо використовувати це замість створення файлу анімації, оскільки це набагато краще рішення. Android Studio вже пропонує за замовчуванням, який animation ви можете використовувати, не створюючи жодного нового XML-файлу. Імена анімації - android.R.anim.slide_in_left та android.R.anim.slide_out_right, і ви можете використовувати їх наступним чином:

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

Вихід:

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


1
android.R ... "Android Studio надає анімацію за замовчуванням", це не для андроїд-студії, вона також може працювати в затемненні, а android.R - специфічний для android. речі на android.R різні на різних apis.
steve moretz

@stevemoretz thaxs bro Я погодився з вашою точкою .. Я виправлю і
оновлю

5

Моя змінена бібліотека підтримки підтримує використання анімаційних зображень (тобто <translate>, <rotate>) та аніматорів об'єктів (тобто <objectAnimator>) для переходів фрагментів. Він реалізований разом з NineOldAndroids . Детальні відомості див. У моїй документації на github.


2

Щодо мене, мені потрібна диракація перегляду:

в -> проведіть праворуч

out -> проведіть пальцем вліво

Тут працює для мене код:

slide_in_right.xml

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

slide_out_left.xml

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

код транзакції:

inline fun FragmentActivity.setContentFragment(
        containerViewId: Int,
        backStack: Boolean = false,
        isAnimate: Boolean = false,
        f: () -> Fragment

): Fragment? {
    val manager = supportFragmentManager
    return f().apply {
        manager.beginTransaction().let {
            if (isAnimate)
                it.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left)

            if (backStack) {
                it.replace(containerViewId, this, "Fr").addToBackStack("Fr").commit()
            } else {
                it.replace(containerViewId, this, "Fr").commit()
            }
        }
    }
}

Android, здається, мерехтить переходи цими анімаціями (особливо перекладними)
Габріель Де Олівейра Роден

@GabrielDeOliveiraRohden як для мене не у всіх випадках
Serg

1

Я вирішую це внизу

Animation anim = AnimationUtils.loadAnimation(this, R.anim.slide);
fg.startAnimation(anim);
this.fg.setVisibility(View.VISIBLE); //fg is a View object indicate fragment
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.