Animuj przejście między fragmentami

284

Próbuję animować przejście między fragmentami. Otrzymałem odpowiedź z następujących
fragmentów Androida i animacji

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

I mój 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>

Ale kiedy spróbowałem, okazało się

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)

Jakieś pomysły? Po sprawdzeniu, translateże jest tam referencja API Honeycomb API . Co mnie ominęło?
Czy istnieje inny sposób animacji przejścia między fragmentami? Dziękuję Ci

Labeeb Panampullan
źródło
użyj ANIMATORA --- nie Animacji! użyj android.R.ANIMATOR.fade_in działa, NIE używaj android.R.ANIM.fade_in - zachowuje się BŁĘDY
użytkownik1269737

Odpowiedzi:

347

Musisz używać nowego android.animationframeworka (animatorów obiektów) zarówno z, FragmentTransaction.setCustomAnimationsjak i FragmentTransaction.setTransition.

Oto przykład użycia setCustomAnimationsz FragmentHideShow.java ApiDemos :

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

a oto odpowiedni animator XML z 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" />

Zauważ, że możesz łączyć wielu animatorów za pomocą <set>, podobnie jak ze starszymi ramami animacji.


EDYCJA : Ponieważ ludzie pytają o wsuwanie / wysuwanie, skomentuję to tutaj.

Wsuwane i wysuwane

Oczywiście można animować translationX, translationY, xoraz ywłaściwości, ale ogólnie slajdy obejmować animowanie zawartości do iz poza ekranem. O ile mi wiadomo, nie ma żadnych właściwości przejścia wykorzystujących wartości względne. Nie przeszkadza to jednak w pisaniu ich samemu. Pamiętaj, że animacje właściwości wymagają po prostu metod pobierających i ustawiających obiekty, które animujesz (w tym przypadku widoków), więc możesz po prostu stworzyć własne getXFraction i setXFractionmetody w podklasie widoku, takie jak:

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);
    }
    ...
}

Teraz możesz animować właściwość „xFraction” w następujący sposób:

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

Zwróć uwagę, że jeśli obiekt, w którym animujesz, nie ma takiej samej szerokości jak jego obiekt nadrzędny, wszystko nie będzie wyglądać dobrze, więc może być konieczne dostosowanie implementacji właściwości w celu dopasowania do Twojego przypadku użycia.

Roman Nurik
źródło
8
Mam fade_in i fade_out do pracy, ale inne w / res / animator dają błędy. I żaden z nich nie wydaje się nawet do wsuwania i wysuwania. Próbowałem napisać własne pliki XML, aby to zrobić, ale wszystko, co mam, to fragmenty na wierzchu fragmentów. Proszę o dodatkową pomoc?
Dave MacLean
A co z tłumaczeniem? Jak wykonać tłumaczenie z wartościami procentowymi w obiekcie objectAnimator, proszę zdefiniować w XML? Nie udało mi się animować AdapterViewFlipper podczas odwracania z pionowymi animacjami slajdów zdefiniowanymi w xml ...
GBouerat
6
Dostaję 11-19 10: 27: 50.912: W / PropertyValuesHolder (23107): Metoda setXFraction () z typem float nie została znaleziona w klasie docelowej android.widget.FrameLayout. Ale w moim XML mam własny widok MyFrameLayout. Jakieś pomysły?
barkside
13
Właściwie, Roman, rada powinna pójść też w drugą stronę: Korzystając z Biblioteki wsparcia, musisz użyć starej ramy animacji (android.R.anim) z FragmentTransaction.setCustomAnimations ao
pjv
1
@RomanNurik ta odpowiedź działała świetnie na większości urządzeń, ale dla niektórych użytkowników (szczególnie na niektórych telefonach Samsung Galaxy S3 / 4) z jakiegoś powodu szerokość nie była zgłaszana podczas animacji, przez co fragment nigdy się nie pojawiał. Udało mi się uruchomić go dla tych użytkowników korzystających z OnPredrawListener, jak pokazano tutaj: mavyasoni9891.blogspot.com/2014/06/…
ajpolt
188

Zrobiłem w ten sposób:

Dodaj tę metodę do wymiany fragmentów z animacji :

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

Musisz dodać cztery animacje do folderu anim, który jest powiązany z zasobem :

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>

Wynik:

wprowadź opis zdjęcia tutaj

Gotowe .

Hiren Patel
źródło
14
Świetne rozwiązanie. Nie jestem jednak pewien, dlaczego zmieniłeś wskazówki dojazdu do RTL. Moja metoda:.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right)
zed
2
Niesamowite rozwiązanie. Podobne podejście i te same pliki animacji działają w przypadku przejścia między czynnościami.
Stan
1
@MikeZriel, res -> anim -> umieść tutaj swój xml
Hiren Patel
3
Dzięki Hiren, zmieniam prędkość (700) na (300) znacznie lepiej i bardziej jak iOS
Mike Zriel
3
LOL, wróciłem z rozwiązaniem. Importowałem android.app.fragment i FragmentManager dla każdej klasy Java. Po sprawdzeniu niektórych materiałów stwierdziłem, że użycie „setCustomAnimations ()” wymaga biblioteki android.support.v4 do zaimportowania. ważne, aby powiedzieć, że powinien to być „support.v4.app”! Wszystkie metody „getFragmentManager ()” zamieniłem na „getSupportFragmentManager ()”, a wszystkie metody importowania „android.app.Fragment / FragmentManager ...” na „android.support.v4.app ....”, a następnie to animacja zaczęła działać dobrze bez awarii ... Jeśli utkniesz w podobnych przypadkach, przeczytaj moje rozwiązanie. Thx Hiren Patel xD
KoreanXcodeWorker
58

Jeśli możesz sobie pozwolić na przywiązanie do Lollipopa i później, wydaje się, że to załatwi sprawę:

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

Mam nadzieję że to pomoże.

scorpiodawg
źródło
1
Chociaż osiągnie to na Lollipop, nie jest to praktycznie praktyczne, ponieważ odsetek urządzeń z Lollipopem jest znikomy (obecnie 1,6% urządzeń z Androidem Lollipop).
Eran Goldin
1
new Slide(...): wywołanie wymaga interfejsu API poziomu 21
Chintan Soni,
co oznacza getKey ()?
Alvaro,
13
@EranGoldin Nic nie trwa wiecznie. Czy wyśmiewałbyś dziś rozwiązanie oparte tylko na systemie Android 2.0+?
Tom
@Tom masz rację. Jednak gdy Twoja aplikacja ma dużą bazę użytkowników, nie możesz po prostu podnieść poziomu interfejsu API. Jeśli większość użytkowników nie będzie już mogła uruchamiać Twojej aplikacji, to nie jest żadne rozwiązanie.
Eran Goldin
47

Nurik „s odpowiedź była bardzo pomocna, ale nie mogę zmusić go do pracy, aż znalazłem to . Krótko mówiąc, jeśli używasz biblioteki kompatybilności (np. SupportFragmentManager zamiast FragmentManager), składnia plików animacji XML będzie inna.

dziwnie
źródło
28

Oto animacja wsuwania / wyjmowania między fragmentami:

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

Używamy objectAnimator.

Oto dwa pliki xml w podfolderze animatora .

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>

Mam nadzieję, że to komuś pomoże.

kirilv
źródło
37
przesunięcie widoku na 2000 pikseli jest bardzo brzydkim rozwiązaniem.
carlo.marinangeli
4
Wyjście_anim tylko dla mnie „wyskakuje” z ekranu, nie animuje się z powrotem na ekranie. Jakieś pomysły? Używam.setCustomAnimations(R.animator.slide_in_left, R.animator.slide_out_right, R.animator.slide_in_left, R.animator.slide_out_right)
pan Pablo
@MrPablo, przyczyną jest prawdopodobnie to, że nie skopiowałeś powyższego kodu. setCustomAnimations należy wywołać przed metodą replace.
Galya,
W takim przypadku, jeśli zastąpię inny fragment animacją i zminimalizuję aplikację bezpośrednio przed upływem limitu czasu animacji lub czasem jej trwania, a następnie ponownie wrócę do aplikacji, wyświetli równolegle poprzedni fragment i bieżący fragment.
Prince
23

Dla każdego, kto zostanie złapany, upewnij się, że setCustomAnimations jest wywoływany przed wywołaniem w celu zastąpienia / dodania podczas budowania transakcji.

Charlie
źródło
12

Implementacja FragmentTransaction dla systemu Android SDK potrzebuje Animatorbiblioteki wsparcia przez chwilę Animation, nie pytaj mnie dlaczego, ale po komentarzu Strangeluka zajrzałem do kodu Androida 4.0.3 i biblioteki wsparcia. Android SDK używa loadAnimator()i obsługuje bibliotekę pomocnicząloadAnimation()

Sherpya
źródło
7

Spróbuj użyć tego prostego i szybkiego rozwiązania. Android oferuje niektóre domyślne 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();

Wynik:

wprowadź opis zdjęcia tutaj

Gowthaman M.
źródło
Wow ... to powinna być zaakceptowana odpowiedź !! Proste i eleganckie rozwiązanie. Jest bardzo płynny w porównaniu z innymi sugerującymi odpowiedziami
Chathura Buddhika