Buat animasi transisi antar fragmen

284

Saya mencoba menghidupkan transisi antara fragmen. Saya mendapat jawaban dari Fragmen dan animasi Android berikut

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

Dan R.anim.slide_in_left saya

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

Tetapi ketika saya mencoba ini itu menunjukkan

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)

Ada ide? Ketika saya memeriksa referensi Honeycomb API translateada di sana. Apa yang saya lewatkan?
Apakah ada cara lain untuk menghidupkan transisi antara fragmen? Terima kasih

Labeeb Panampullan
sumber
gunakan ANIMATOR --- bukan Animasi! gunakan android.R.ANIMATOR.fade_in bekerja, JANGAN gunakan android.R.ANIM.fade_in - ini memiliki perilaku BUGS
user1269737

Jawaban:

348

Anda perlu menggunakan baru android.animationkerangka kerja (objek animator) dengan FragmentTransaction.setCustomAnimationsserta FragmentTransaction.setTransition.

Berikut ini contoh penggunaan setCustomAnimationsdari ApiDemos ' FragmentHideShow.java :

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

dan inilah animator XML yang relevan dari 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" />

Perhatikan bahwa Anda dapat menggabungkan beberapa animator menggunakan <set>, seperti yang Anda bisa dengan kerangka animasi yang lebih lama.


EDIT : Karena orang-orang bertanya tentang slide-in / slide-out, saya akan berkomentar di sini.

Slide-in dan slide-out

Anda tentu saja dapat menghidupkan translationX, translationY, x, dan yproperti, tetapi umumnya slide melibatkan menghidupkan konten ke dan dari luar layar. Sejauh yang saya tahu tidak ada properti transisi yang menggunakan nilai relatif. Namun, ini tidak menghalangi Anda untuk menulisnya sendiri. Ingat bahwa animasi properti hanya membutuhkan metode pengambil dan penyetel pada objek yang Anda animasikan (dalam tampilan kasus ini), jadi Anda bisa membuatnya sendiri getXFraction dan setXFractionmetode pada subkelas tampilan Anda, seperti ini:

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

Sekarang Anda dapat menghidupkan properti 'xFraction', seperti ini:

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

Perhatikan bahwa jika objek yang Anda animasikan tidak memiliki lebar yang sama dengan induknya, segalanya tidak akan terlihat benar, jadi Anda mungkin perlu mengubah implementasi properti Anda agar sesuai dengan use case Anda.

Roman Nurik
sumber
8
Saya mendapatkan fade_in dan fade_out untuk bekerja, tetapi yang lain di / res / animator memberikan kesalahan. Dan tak satu pun dari mereka yang tampaknya meluncur masuk dan keluar. Saya sudah mencoba menulis xml saya sendiri untuk melakukan ini, tetapi yang akhirnya saya dapatkan adalah fragmen di atas fragmen. Tolong bantu lagi?
Dave MacLean
Dan bagaimana dengan terjemahannya? Bagaimana Anda melakukan terjemahan dengan nilai dalam persentase dalam objekAnimator yang ditentukan dalam XML? Saya tidak berhasil menghidupkan AdapterViewFlipper selama membalik dengan mendefinisikan animasi slide vertikal di xml ...
GBouerat
6
Saya mendapatkan 11-19 10: 27: 50.912: W / PropertyValuesHolder (23107): Metode setXFraction () dengan tipe float yang tidak ditemukan pada kelas target kelas android.widget.FrameLayout. Tetapi dalam XML saya, saya memiliki tampilan kustom MyFrameLayout. Ada ide?
barkside
13
Sebenarnya, Roman, sarannya juga harus sebaliknya: Ketika menggunakan Support Library, Anda perlu menggunakan kerangka animasi lama (android.R.anim) dengan FragmentTransaction.setCustomAnimations ao
pjv
1
@RomanNurik jawaban ini bekerja sangat baik pada sebagian besar perangkat, tetapi untuk beberapa pengguna (khususnya pada beberapa ponsel Samsung Galaxy S3 / 4) lebar tidak dilaporkan selama animasi karena suatu alasan, menyebabkan fragmen tidak pernah muncul. Saya bisa membuatnya berfungsi untuk para pengguna menggunakan OnPredrawListener seperti yang ditunjukkan di sini: mavyasoni9891.blogspot.com/2014/06/…
ajpolt
188

Saya telah melakukan ini:

Tambahkan metode ini untuk mengganti fragmen dengan Animasi :

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

Anda harus menambahkan empat animasi di folder anim yang dikaitkan dengan sumber daya :

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>

Keluaran:

masukkan deskripsi gambar di sini

Selesai .

Hiren Patel
sumber
14
Solusi bagus Namun saya tidak yakin mengapa Anda menukar arah ke RTL. Metode saya:.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right)
zed
2
Solusi yang luar biasa. Pendekatan serupa dan file animasi yang sama berfungsi untuk transisi antar aktivitas.
Stan
1
@MikeZriel, res -> anim -> letakkan xml Anda di sini
Hiren Patel
3
Terima kasih Hiren, saya mengubah kecepatan (700) menjadi (300) jauh lebih baik dan lebih seperti iOS
Mike Zriel
3
LOL, saya kembali dengan solusi. Saya mengimpor android.app.fragment dan FragmentManager di setiap kelas java. Setelah memeriksa beberapa materi, saya menemukan bahwa menggunakan 'setCustomAnimations ()' membutuhkan perpustakaan android.support.v4 yang akan diimpor. penting untuk mengatakan bahwa itu harus 'support.v4.app'! Saya mengganti semua metode 'getFragmentManager ()' dengan 'getSupportFragmentManager ()', dan semua impor 'android.app.Fragment / FragmentManager ...' ke 'android.support.v4.app ....', lalu ini animasi mulai bekerja dengan baik tanpa crash ... Jika kalian terjebak dalam kasus yang sama, baca solusi saya. Thx Hiren Patel xD
KoreanXcodeWorker
58

Jika Anda mampu mengikat diri hanya dengan Lollipop dan yang lebih baru, ini sepertinya bisa dilakukan:

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

Semoga ini membantu.

scorpiodawg
sumber
1
Sementara itu akan mencapainya di Lollipop, itu hampir tidak praktis karena persentase perangkat yang menjalankan Lollipop dapat diabaikan (saat ini 1,6% perangkat Android menjalankan Lollipop).
Eran Goldin
1
new Slide(...): panggilan membutuhkan API level 21
Chintan Soni
apa artinya getKey ()?
Alvaro
13
@EranGoldin Tidak ada yang bertahan selamanya .. maukah Anda mencemooh solusi Android 2.0+ hari ini?
Tom
@Tom Anda ada benarnya. Namun ketika aplikasi Anda memiliki basis pengguna yang besar, Anda tidak bisa hanya menabrak tingkat API. Jika sebagian besar pengguna Anda tidak akan dapat menjalankan aplikasi Anda lagi setelah itu, itu bukan solusi sama sekali.
Eran Goldin
47

Jawaban Nurik sangat membantu, tetapi saya tidak bisa bekerja sampai saya menemukan ini . Singkatnya, jika Anda menggunakan pustaka kompatibilitas (mis. SupportFragmentManager alih-alih FragmentManager), sintaksis file animasi XML akan berbeda.

strangeluck
sumber
28

Berikut ini animasi slide masuk / keluar antara fragmen:

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

Kami menggunakan objectAnimator.

Berikut adalah dua file xml dalam subfolder animator .

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>

Saya harap itu akan membantu seseorang.

Kirilv
sumber
37
memindahkan tampilan untuk 2000 px, adalah solusi yang sangat jelek.
carlo.marinangeli
4
The exit_anim hanya "muncul" dari layar untuk saya, itu tidak menghidupkan kembali di layar. Ada ide? Saya menggunakan.setCustomAnimations(R.animator.slide_in_left, R.animator.slide_out_right, R.animator.slide_in_left, R.animator.slide_out_right)
Tn. Pablo
@ MrPablo, alasannya mungkin karena Anda belum menyalin kode yang disisipkan di atas. setCustomAnimations harus dipanggil sebelum metode ganti.
Galya
Dalam hal ini, Jika saya mengganti fragmen lain dengan animasi dan saya memang meminimalkan aplikasi segera sebelum waktu animasi habis atau durasi kembali ke aplikasi, itu akan menampilkan fragmen sebelumnya dan paralel fragmen saat ini.
Pangeran
23

Bagi siapa pun yang ketahuan, pastikan setCustomAnimations dipanggil sebelum panggilan untuk mengganti / menambah saat membangun transaksi.

Charlie
sumber
12

Implementasi Android SDK dari FragmentTransaction Animatormembutuhkan perpustakaan dukungan sementara menginginkan Animation, jangan tanya mengapa, tetapi setelah komentar strangeluk saya melihat ke kode android 4.0.3 dan perpustakaan dukungan. Android SDK menggunakan loadAnimator()dan mendukung penggunaan perpustakaanloadAnimation()

sherpya
sumber
7

Coba gunakan solusi sederhana dan cepat ini. Android menyediakan beberapa default 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();

Keluaran:

masukkan deskripsi gambar di sini

Gowthaman M
sumber
Woow .. ini seharusnya jawaban yang diterima !! Solusi sederhana dan elegan. Ini sangat halus dibandingkan dengan yang lain menyarankan jawaban
Chathura Buddhika