Fragmenty Androida i animacja

265

Jak wdrożyć funkcję przesuwania, której używa na przykład klient Gmaila o strukturze plastra miodu?

Może TransactionManagersobie z tym poradzić automatycznie, dodając i usuwając Fragmenty, trudno jest to przetestować, ponieważ emulator jest pokazem slajdów :)

alexanderblom
źródło

Odpowiedzi:

388

Aby animować przejście między fragmentami lub animować proces pokazywania lub ukrywania fragmentu, którego używasz Fragment Managerdo utworzenia pliku Fragment Transaction.

W ramach każdej transakcji fragmentu możesz określić animacje wchodzące i wychodzące, które będą używane odpowiednio do pokazywania i ukrywania (lub obu, gdy używana jest zamiana).

Poniższy kod pokazuje, jak zastąpić fragment, przesuwając jeden fragment i przesuwając drugi na swoim miejscu.

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

Aby osiągnąć to samo z ukryciem lub pokazaniem fragmentu, który po prostu nazwiesz, ft.showlub ft.hideprzekazaniem fragmentu, który chcesz odpowiednio pokazać lub ukryć.

W celach informacyjnych definicje animacji XML wykorzystują objectAnimatorznacznik. Przykład slide_in_left może wyglądać mniej więcej tak:

<?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>
Reto Meier
źródło
57
Kiedy próbowałem, pokazuje RuntimeException: Nieznana nazwa animatora: tłumacz .
Labeeb Panampullan
3
Upewnij się, że animacje zdefiniowane w slide_in_left i right są zbudowane przy użyciu zestawu definicji objectAnimator zamiast starej definicji animacji.
Reto Meier,
7
To bardzo pomogło. Byłem na dobrej drodze, ale nie dostałem się tam. Dla innych czytelników możesz również mieć android: interpolator jako atrybut, z określonym ulubionym (np. „@Android: interpolator / liniowy”). Domyślnie jest to „@ android: interpolator / accelerate_decelerate”.
Dave MacLean
6
Mam interfejs API poziomu 7 z kompatybilnymi interfejsami API. Czy istnieje sposób na animowanie Fragmentów?
Jarrod Smith
5
@JarrodSmith możesz spróbować użyć biblioteki kompatybilności, takiej jak NineOldAndroids, aby sprowadzić API Honeycomb API do Eclair.
Pan S
249

Jeśli nie musisz korzystać z biblioteki wsparcia, spójrz na odpowiedź Romana .

Ale jeśli chcesz użyć biblioteki wsparcia , musisz użyć starej ramy animacji, jak opisano poniżej.

Po zapoznaniu się z odpowiedziami Reto i blindstuff otrzymałem następujący kod.

Fragmenty wydają się przesuwać z prawej strony i przesuwać w lewo po naciśnięciu tyłu.

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

Kolejność jest ważna. Oznacza to, że musisz setCustomAnimations()wcześniej zadzwonić, replace()inaczej animacja nie zadziała!

Następnie pliki te należy umieścić w folderze 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>

Czas trwania animacji można zmienić na dowolną z domyślnych wartości, takich jak @android:integer/config_shortAnimTimelub na dowolną inną liczbę.

Zauważ, że jeśli pomiędzy wymianami fragmentów nastąpi zmiana konfiguracji (na przykład obrót), działanie wsteczne nie jest animowane. Jest to udokumentowany błąd, który nadal występuje w wersji 20 biblioteki wsparcia.

dmanargias
źródło
47
To mnie uratowało. Uwaga: należy zwrócić uwagę na kolejność , która jest ważna , co oczywiście mi brakowało za pierwszym razem. Oznacza to, że musisz wywołać setCustomAnimations () przed replace ().
Stephen Kidson
3
Próbowałem zaimplementować na swoich fragmentach. Napisałem wszystko, jak wspomniałeś, ale logcat mówi: nieznana nazwa tłumacza tłumacz Jak mogę rozwiązać ten problem? Nawiasem mówiąc, dzwonię do mojego fragmentu w
Szufladzie
Działa świetnie, ale okazuje się, że zbudowanie go za pomocą narzędzi do kompilacji 21.1 generuje błąd: „Nieprawidłowa nazwa pliku: musi zawierać tylko małe litery i cyfry ([a-z0-9_.])”. Sugeruję edycję nazw plików w odpowiedzi na pop_enter.xml i pop_exit.xml.
smichak,
Świetne rozwiązanie i działa świetnie po naciśnięciu przycisku Wstecz. Mam tylko jedno pytanie: jeśli chcę utworzyć niestandardowy przycisk BackButton, jaki kod powinienem wywołać, aby zreplikować zachowanie z przycisku Wstecz?
Thomas Teilmann,
1
Thomas, jeśli chcesz się wycofać, powinieneś zaimplementować ten formularz: .setCustomAnimations (R.anim.pop_enter, R.anim.pop_exit, R.anim.enter, R.anim.exit)
Alex Zaraos
26

Zdecydowanie sugeruję użycie tego zamiast tworzenia pliku animacji, ponieważ jest to znacznie lepsze rozwiązanie. Android Studio zapewnia już domyślną opcję, animation której można używać bez tworzenia nowego pliku XML. Nazwy animacji to android.R.anim.slide_in_left i android.R.anim.slide_out_right i można ich używać w następujący sposób:

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

Wynik:

wprowadź opis zdjęcia tutaj

Gowthaman M.
źródło
1
android. rzeczy na Androida.R różnią się w zależności od api.
steve moretz
@stevemoretz thaxs bro Zgodziłem się na twój punkt .. Poprawię i zaktualizuję swoją odpowiedź ...
Gowthaman M
5

Moja zmodyfikowana biblioteka obsługi obsługuje zarówno wyświetlanie animacji (tj. <translate>, <rotate>), Jak i animatorów obiektów (tj. <objectAnimator>) Dla przejść fragmentów. Jest zaimplementowany z NineOldAndroids . Szczegółowe informacje znajdują się w mojej dokumentacji na github.

mark.kedzierski
źródło
2

Jeśli chodzi o mnie, potrzebuję widoku diraction:

w -> przeciągnij od prawej

na zewnątrz -> przeciągnij w lewo

Oto działa dla mnie kod:

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>

kod transakcji:

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()
            }
        }
    }
}
Serg Burlaka
źródło
Android wydaje się migotać przy przejściach z tymi animacjami (zwłaszcza tymi przetłumaczonymi)
Gabriel De Oliveira Rohden,
@GabrielDeOliveiraRohden jak dla mnie nie we wszystkich klasach
Serg
1

Rozwiązuję to w następujący sposób

Animation anim = AnimationUtils.loadAnimation(this, R.anim.slide);
fg.startAnimation(anim);
this.fg.setVisibility(View.VISIBLE); //fg is a View object indicate fragment
Shakawat Hossain
źródło