Berikut skenarionya: Aktivitas mengandung fragmen A
, yang pada gilirannya menggunakan getChildFragmentManager()
untuk menambahkan fragmen A1
dan A2
di nya onCreate
seperti:
getChildFragmentManager()
.beginTransaction()
.replace(R.id.fragmentOneHolder, new FragmentA1())
.replace(R.id.fragmentTwoHolder, new FragmentA2())
.commit()
Sejauh ini bagus, semuanya berjalan seperti yang diharapkan.
Kami kemudian menjalankan transaksi berikut di Aktivitas:
getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations(anim1, anim2, anim1, anim2)
.replace(R.id.fragmentHolder, new FragmentB())
.addToBackStack(null)
.commit()
Selama transisi, enter
animasi untuk fragmen B
berjalan dengan benar, tetapi fragmen A1 dan A2 hilang seluruhnya . Saat kami mengembalikan transaksi dengan tombol Kembali, mereka menginisialisasi dengan benar dan ditampilkan secara normal selama popEnter
animasi.
Dalam pengujian singkat saya, itu menjadi lebih aneh - jika saya mengatur animasi untuk fragmen anak (lihat di bawah), exit
animasi berjalan sesekali saat kita menambahkan fragmenB
getChildFragmentManager()
.beginTransaction()
.setCustomAnimations(enter, exit)
.replace(R.id.fragmentOneHolder, new FragmentA1())
.replace(R.id.fragmentTwoHolder, new FragmentA2())
.commit()
Efek yang ingin saya capai sederhana - Saya ingin animasi exit
(atau haruskah popExit
?) Pada fragmen A
(anim2) berjalan, menganimasikan seluruh container, termasuk turunannya yang bersarang.
Apakah ada cara untuk mencapai itu?
Edit : Silakan temukan kasus uji di sini
Sunting2 : Terima kasih kepada @StevenByle karena telah mendorong saya untuk terus mencoba dengan animasi statis. Rupanya Anda dapat menyetel animasi pada basis per-op (tidak global untuk seluruh transaksi), yang berarti anak-anak dapat memiliki set animasi statis tak terbatas, sementara induknya dapat memiliki animasi yang berbeda dan semuanya dapat dilakukan dalam satu transaksi . Lihat pembahasan di bawah ini dan proyek kasus uji yang diperbarui .
R.id.fragmentHolder
dengan A, A1, A2, dll?changeFragment
metode ini hanya satu kali?Jawaban:
Untuk menghindari pengguna melihat fragmen bertingkat menghilang saat fragmen induk dihapus / diganti dalam transaksi, Anda dapat "mensimulasikan" fragmen yang masih ada dengan memberikan gambarnya, seperti yang muncul di layar. Gambar ini akan digunakan sebagai latar belakang untuk wadah fragmen bersarang sehingga meskipun tampilan dari fragmen bersarang hilang, gambar akan mensimulasikan keberadaannya. Selain itu, saya tidak melihat kehilangan interaktivitas dengan tampilan fragmen bersarang sebagai masalah karena menurut saya Anda tidak ingin pengguna menindaklanjutinya saat mereka baru saja dalam proses penghapusan (mungkin sebagai tindakan pengguna sebagai baik).
Saya telah membuat sedikit contoh dengan menyiapkan gambar latar belakang (sesuatu yang mendasar).
sumber
Jadi tampaknya ada banyak solusi berbeda untuk ini, tetapi berdasarkan jawaban @ Jayd16, saya rasa saya telah menemukan solusi penampung-semua yang cukup solid yang masih memungkinkan animasi transisi khusus pada fragmen anak, dan tidak perlu dilakukan cache bitmap tata letak.
Miliki
BaseFragment
kelas yang diperluasFragment
, dan buat semua fragmen Anda memperluas kelas itu (bukan hanya fragmen anak).Di
BaseFragment
kelas itu, tambahkan yang berikut ini:Sayangnya, hal itu membutuhkan refleksi; namun, karena solusi ini adalah untuk pustaka dukungan, Anda tidak akan mengambil risiko penerapan yang mendasari berubah kecuali Anda memperbarui pustaka dukungan. Jika Anda membuat pustaka dukungan dari sumber, Anda dapat menambahkan pengakses untuk ID sumber daya animasi berikutnya ke
Fragment.java
dan menghapus kebutuhan refleksi.Solusi ini menghilangkan kebutuhan untuk "menebak" durasi animasi induk (sehingga animasi "tidak melakukan apa-apa" akan memiliki durasi yang sama dengan animasi keluar induk), dan memungkinkan Anda untuk tetap melakukan animasi kustom pada fragmen turunan (misalnya jika Anda ' kembali menukar fragmen anak dengan animasi yang berbeda).
sumber
mNextAnim
sekarang berada di dalam suatumAnimationInfo
objek. Anda dapat mengaksesnya seperti ini:Field animInfoField = Fragment.class.getDeclaredField("mAnimationInfo");
animInfoField.setAccessible(true);
Object animationInfo = animInfoField.get(fragment);
Field nextAnimField = animationInfo.getClass().getDeclaredField("mNextAnim");
val nextAnimResource = nextAnimField.getInt(animationInfo);
untuk mengganti barisint nextAnimResource = nextAnimField.getInt(fragment);
Saya dapat menemukan solusi yang cukup bersih. IMO adalah yang paling tidak hacky, dan sementara ini secara teknis solusi "menggambar bitmap" setidaknya diabstraksikan oleh fragmen lib.
Pastikan frags anak Anda mengganti kelas induk dengan ini:
Jika kita memiliki animasi keluar pada anak frags, mereka akan dianimasikan alih-alih berkedip. Kita bisa memanfaatkan ini dengan memiliki animasi yang hanya menggambar fragmen turunan pada alfa penuh selama suatu durasi. Dengan cara ini, mereka akan tetap terlihat di fragmen induk saat dianimasikan, memberikan perilaku yang diinginkan.
Satu-satunya masalah yang dapat saya pikirkan adalah melacak durasi itu. Saya mungkin bisa mengaturnya ke angka besar tapi saya khawatir itu mungkin memiliki masalah kinerja jika masih menggambar animasi itu di suatu tempat.
sumber
Saya memposting solusi saya untuk kejelasan. Solusinya cukup sederhana. Jika Anda mencoba meniru animasi transaksi fragmen induk, cukup tambahkan animasi khusus ke transaksi fragmen turunan dengan durasi yang sama. Oh dan pastikan Anda mengatur animasi khusus sebelum add ().
Xml untuk R.anim.none (Orang tua saya masuk / keluar waktu animasi adalah 250ms)
sumber
fragmentTransaction.setCustomAnimations(R.anim.none, 0, R.anim.none, R.anim.none)
Saya mengerti bahwa ini mungkin tidak dapat menyelesaikan masalah Anda sepenuhnya, tetapi mungkin itu akan sesuai dengan kebutuhan orang lain, Anda dapat menambahkan
enter
/exit
danpopEnter
/popExit
animasi ke anak-anak AndaFragment
yang tidak benar-benar memindahkan / menghidupkannyaFragment
. Selama animasi memiliki durasi / offset yang sama denganFragment
animasi induknya , animasi tersebut akan tampak bergerak / beranimasi dengan animasi induknya.sumber
Anda dapat melakukan ini di fragmen anak.
sumber
@@@@@@@@@@@@@@@@@@@@@@@@@@@
EDIT: Saya akhirnya tidak menerapkan solusi ini karena ada masalah lain yang dimilikinya. Square baru-baru ini keluar dengan 2 library yang menggantikan fragmen. Saya akan mengatakan ini sebenarnya mungkin alternatif yang lebih baik daripada mencoba meretas fragmen untuk melakukan sesuatu yang tidak diinginkan Google.
http://corner.squareup.com/2014/01/mortar-and-flow.html
@@@@@@@@@@@@@@@@@@@@@@@@@@@
Saya pikir saya akan memberikan solusi ini untuk membantu orang-orang yang memiliki masalah ini di masa depan. Jika Anda menelusuri percakapan poster asli dengan orang lain, dan melihat kode yang dia posting, Anda akan melihat poster asli akhirnya sampai pada kesimpulan menggunakan animasi tanpa operasi pada fragmen turunan sambil menganimasikan fragmen induk. Solusi ini tidak ideal karena memaksa Anda untuk melacak semua fragmen turunan, yang dapat merepotkan saat menggunakan ViewPager dengan FragmentPagerAdapter.
Karena saya menggunakan Fragmen Anak di semua tempat, saya mendapatkan solusi ini yang efisien, dan modular (sehingga dapat dengan mudah dihapus) jika mereka memperbaikinya dan animasi tanpa operasi ini tidak lagi diperlukan.
Ada banyak cara untuk menerapkan ini. Saya memilih untuk menggunakan singleton, dan saya menyebutnya ChildFragmentAnimationManager. Ini pada dasarnya akan melacak fragmen anak untuk saya berdasarkan induknya dan akan menerapkan animasi tanpa operasi ke anak-anak ketika diminta.
Selanjutnya Anda perlu memiliki kelas yang memperluas Fragmen yang diperluas oleh semua Fragmen Anda (setidaknya Fragmen Anak Anda). Saya sudah memiliki kelas ini, dan saya menyebutnya BaseFragment. Saat tampilan fragmen dibuat, kami menambahkannya ke ChildFragmentAnimationManager, dan menghapusnya saat dihancurkan. Anda bisa melakukan ini onAttach / Detach, atau metode lain yang cocok secara berurutan. Logika saya untuk memilih Buat / Hancurkan Tampilan adalah karena jika Fragmen tidak memiliki Tampilan, saya tidak peduli untuk menganimasinya agar terus terlihat. Pendekatan ini juga akan bekerja lebih baik dengan ViewPager yang menggunakan Fragmen karena Anda tidak akan melacak setiap Fragment yang dipegang FragmentPagerAdapter, melainkan hanya 3.
Sekarang semua Fragmen Anda disimpan dalam memori oleh fragmen induk, Anda dapat memanggil animate-nya seperti ini, dan fragmen turunan Anda tidak akan hilang.
Juga, asal Anda memilikinya, berikut adalah file no_anim.xml yang ada di folder res / anim Anda:
Sekali lagi, menurut saya solusi ini tidak sempurna, tetapi jauh lebih baik daripada untuk setiap contoh Anda memiliki Fragmen Anak, menerapkan kode khusus di fragmen induk untuk melacak setiap anak. Saya pernah ke sana, dan itu tidak menyenangkan.
sumber
Saya rasa saya menemukan solusi yang lebih baik untuk masalah ini daripada mengambil snapshot fragmen saat ini ke bitmap seperti yang disarankan Luksprog.
Triknya adalah bersembunyi fragmen yang sedang dihilangkan atau dilepas dan hanya setelah animasi selesai, fragmen tersebut akan dihapus atau dilepas dalam transaksi fragmennya sendiri.
Bayangkan kita memiliki
FragmentA
danFragmentB
, keduanya dengan sub fragmen. Sekarang saat Anda biasanya melakukan:Sebaliknya Anda melakukannya
Sekarang untuk implementasi Fragmen:
sumber
Saya mengalami masalah yang sama dengan fragmen peta. Itu terus menghilang selama animasi keluar dari fragmen yang mengandungnya. Solusinya adalah dengan menambahkan animasi untuk fragmen peta anak yang akan membuatnya tetap terlihat selama animasi keluar dari fragmen induk. Animasi fragmen turunan mempertahankan alfa 100% selama periode durasinya.
Animasi: res / animator / keep_child_fragment.xml
Animasi tersebut kemudian diterapkan saat fragmen peta ditambahkan ke fragmen induk.
Fragmen induk
Terakhir, durasi animasi fragmen turunan disetel dalam file sumber daya.
nilai / integers.xml
sumber
Untuk menganimasikan hilangnya fragmen yang tidak diinginkan, kita dapat memaksa pop back stack di ChildFragmentManager. Ini akan mengaktifkan animasi transisi. Untuk melakukan ini, kita perlu mengikuti acara OnBackButtonPressed atau mendengarkan perubahan backstack.
Berikut adalah contoh dengan kode.
sumber
Saya baru-baru ini mengalami masalah ini dalam pertanyaan saya: Transisi fragmen bersarang yang salah
Saya memiliki solusi yang menyelesaikan ini tanpa menyimpan bitmap, atau menggunakan refleksi atau metode lain yang tidak memuaskan.
Contoh proyek dapat dilihat di sini: https://github.com/zafrani/NestedFragmentTransitions
GIF dari efeknya dapat dilihat di sini: https://imgur.com/94AvrW4
Dalam contoh saya, ada 6 fragmen anak, dipisahkan antara dua fragmen induk. Saya dapat mencapai transisi untuk masuk, keluar, pop, dan dorong tanpa masalah. Perubahan konfigurasi dan penekanan kembali juga berhasil ditangani.
Sebagian besar solusi ada di fungsi onCreateAnimator BaseFragment saya (fragmen diperpanjang oleh anak-anak dan orang tua saya) yang terlihat seperti ini:
Aktivitas dan fragmen induk bertanggung jawab untuk menyetel status boolean ini. Lebih mudah untuk melihat bagaimana dan di mana dari proyek contoh saya.
Saya tidak menggunakan fragmen dukungan dalam contoh saya, tetapi logika yang sama dapat digunakan dengan mereka dan fungsi onCreateAnimation mereka
sumber
Cara sederhana untuk memperbaiki masalah ini adalah menggunakan
Fragment
kelas dari pustaka ini, bukan dari kelas fragmen pustaka standar:https://github.com/marksalpeter/contract-fragment
Sebagai catatan tambahan, paket ini juga berisi pola delegasi berguna yang disebut
ContractFragment
yang mungkin berguna bagi Anda untuk membangun aplikasi dengan memanfaatkan hubungan fragmen induk-anak.sumber
Dari jawaban @kcoppock di atas,
jika Anda memiliki Activity-> Fragment-> Fragments (multiple stacking, berikut membantu), sedikit edit untuk jawaban terbaik IMHO.
sumber
Masalah saya adalah pada penghapusan fragmen induk (ft.remove (fragment)), animasi anak tidak terjadi.
Masalah dasarnya adalah bahwa fragmen turunan segera DIHANCURKAN SEBELUM animasi keluar fragmen induk.
Animasi kustom fragmen turunan tidak dijalankan saat penghapusan Fragmen Induk
Seperti yang telah dihindari orang lain, menyembunyikan ORANGTUA (dan bukan anak) sebelum penghapusan PARENT adalah cara yang harus dilakukan.
Jika Anda benar-benar ingin menghapus induk, Anda mungkin harus menyiapkan pendengar pada animasi khusus Anda untuk mengetahui kapan animasi tersebut berakhir, sehingga Anda dapat dengan aman melakukan beberapa penyelesaian pada Fragmen Induk (hapus). Jika Anda tidak melakukan ini, pada waktunya, Anda bisa membunuh animasinya. Animasi NB dilakukan pada antrian asynchronous-nya sendiri.
BTW Anda tidak memerlukan animasi khusus pada fragmen turunan, karena mereka akan mewarisi animasi induk.
sumber
Masalah diperbaiki di
androidx.fragment:fragment:1.2.0-alpha02
. Lihat https://issuetracker.google.com/issues/116675313 untuk detail lebih lanjut.sumber
Utas lama, tetapi jika seseorang tersandung di sini:
Semua pendekatan di atas terasa sangat tidak menarik bagi saya, solusi bitmap sangat kotor dan tidak berkinerja baik; yang lain mengharuskan fragmen turunan mengetahui tentang durasi transisi yang digunakan dalam transaksi yang digunakan untuk membuat fragmen turunan yang dimaksud. Solusi yang lebih baik di mata saya seperti berikut ini:
Kami hanya menyembunyikan fragmen saat ini dan menambahkan fragmen baru, ketika animasi telah selesai, kami menghapus fragmen lama. Dengan cara ini ditangani di satu tempat dan tidak ada bitmap yang dibuat.
sumber