TL; DR: Saya mencari sampel kerja lengkap dari skenario yang akan saya sebut sebagai "animasi tiga-fragmen Gmail". Secara khusus, kami ingin memulai dengan dua fragmen, seperti ini:
Setelah beberapa acara UI (misalnya, mengetuk sesuatu di Fragment B), kami ingin:
- Fragmen A untuk menggeser layar ke kiri
- Fragmen B untuk meluncur ke tepi kiri layar dan menyusut untuk mengambil tempat yang dikosongkan oleh Fragment A
- Fragmen C untuk meluncur dari sisi kanan layar dan untuk mengambil tempat yang dikosongkan oleh Fragment B
Dan, pada tombol BACK tekan, kami ingin set operasi dibalik.
Sekarang, saya telah melihat banyak implementasi parsial; Saya akan mengulas empat di antaranya di bawah ini. Selain tidak lengkap, mereka semua memiliki masalah.
@Reto Meier menyumbangkan jawaban populer ini untuk pertanyaan dasar yang sama, yang menunjukkan bahwa Anda akan menggunakannya setCustomAnimations()
dengan a FragmentTransaction
. Untuk skenario dua fragmen (misalnya, Anda hanya melihat Fragmen A pada awalnya, dan ingin menggantinya dengan Fragmen B baru menggunakan efek animasi), saya setuju sepenuhnya. Namun:
- Karena Anda hanya dapat menentukan satu animasi "dalam" dan satu "keluar", saya tidak dapat melihat bagaimana Anda akan menangani semua animasi berbeda yang diperlukan untuk skenario tiga-fragmen
- Dalam
<objectAnimator>
kode sampelnya menggunakan posisi kabel dalam piksel, dan itu tampaknya tidak praktis mengingat berbagai ukuran layar, namunsetCustomAnimations()
membutuhkan sumber daya animasi, menghalangi kemungkinan mendefinisikan hal-hal ini di Jawa - Saya bingung bagaimana objek animator untuk skala terkait dengan hal-hal seperti
android:layout_weight
dalamLinearLayout
untuk mengalokasikan ruang berdasarkan persentase - Saya bingung bagaimana Fragment C ditangani sejak awal (
GONE
?android:layout_weight
Dari0
? Pra-animasi ke skala 0? Sesuatu yang lain?)
@Roman Nurik menunjukkan bahwa Anda dapat menghidupkan properti apa pun , termasuk properti yang Anda tetapkan sendiri. Itu dapat membantu menyelesaikan masalah posisi terprogram, dengan biaya menemukan subclass manajer tata letak kustom Anda sendiri. Itu membantu beberapa orang, tetapi saya masih bingung dengan sisa solusi Reto.
Penulis entri pastebin ini menunjukkan beberapa pseudocode yang menggiurkan, pada dasarnya mengatakan bahwa ketiga fragmen akan berada di dalam wadah pada awalnya, dengan Fragment C yang tersembunyi di awal melalui hide()
operasi transaksi. Kami kemudian show()
C dan hide()
A ketika acara UI terjadi. Namun, saya tidak melihat bagaimana itu menangani fakta bahwa B berubah ukuran. Itu juga bergantung pada fakta bahwa Anda tampaknya dapat menambahkan beberapa fragmen ke wadah yang sama, dan saya tidak yakin apakah itu perilaku yang dapat diandalkan dalam jangka panjang (belum lagi harus rusak findFragmentById()
, meskipun saya bisa hidup dengan itu).
Penulis posting blog ini menunjukkan bahwa Gmail tidak menggunakan setCustomAnimations()
sama sekali, melainkan langsung menggunakan animator objek ("Anda hanya mengubah margin kiri tampilan root + mengubah lebar tampilan kanan"). Namun, ini masih merupakan solusi dua-fragmen AFAICT, dan implementasinya sekali lagi menunjukkan dimensi kabel dalam piksel.
Saya akan terus menghubungkan ini, jadi saya mungkin akan menjawab ini sendiri suatu hari nanti, tetapi saya benar-benar berharap bahwa seseorang telah menemukan solusi tiga-fragmen untuk skenario animasi ini dan dapat memposting kode (atau tautannya). Animasi di Android membuat saya ingin mencabut rambut saya, dan Anda yang telah melihat saya tahu bahwa ini adalah upaya yang tidak membuahkan hasil.
sumber
Jawaban:
Mengunggah proposal saya di github (Bekerja dengan semua versi android meskipun melihat akselerasi perangkat keras sangat disarankan untuk animasi semacam ini. Untuk perangkat yang tidak dipercepat perangkat keras, implementasi caching bitmap harus sesuai dengan lebih baik)
Demo video dengan animasinya ada di sini (Laju frame rate dari screen cast. Performa sebenarnya sangat cepat)
Pemakaian:
Penjelasan :
Membuat RelativeLayout kustom baru (ThreeLayout) dan 2 animasi kustom (MyScalAnimation, MyTranslateAnimation)
ThreeLayout
mendapatkan bobot panel kiri sebagai param, dengan asumsi tampilan lain yang terlihatweight=1
.Sehingga
new ThreeLayout(context,3)
menciptakan tampilan baru dengan 3 anak dan panel kiri dengan 1/3 dari total layar. Tampilan lain menempati semua ruang yang tersedia.Skala dan Terjemahan animasi sebenarnya mengubah ukuran dan memindahkan tampilan dan bukan pseudo- [skala, pindah]. Perhatikan bahwa
fillAfter(true)
tidak digunakan di mana pun.View2 adalah right_of View1
dan
View3 adalah right_of View2
Setelah menetapkan aturan ini, RelativeLayout menangani semua hal lainnya. Animasi mengubah
margins
(bergerak) dan[width,height]
dalam skalaUntuk mengakses setiap anak (sehingga Anda dapat mengembang dengan Fragmen Anda, Anda dapat menelepon
Di bawah ini ditunjukkan 2 animasi
Tahap 1
Tahap 2
sumber
View
lebih kecil), tetapi di Gmail / Email, kami tidak mendapatkan font yang lebih kecil, hanya lebih sedikit kata.scaleX
nilaiView
, meskipun saya mungkin salah mengartikan hal-hal.OK, ini solusi saya sendiri, berasal dari aplikasi Email AOSP, sesuai saran @ Christopher dalam komentar pertanyaan.
https://github.com/commonsguy/cw-omnibus/tree/master/Animation/ThreePane
Solusi @ lemahwire mengingatkan saya, meskipun ia menggunakan klasik
Animation
daripada animator, dan ia menggunakanRelativeLayout
aturan untuk menegakkan penentuan posisi. Dari sudut pandang karunia, ia mungkin akan mendapatkan karunia itu, kecuali jika orang lain dengan solusi yang lebih licin belum mengirimkan jawaban.Singkatnya,
ThreePaneLayout
dalam proyek itu adalahLinearLayout
subkelas, yang dirancang untuk bekerja di lanskap dengan tiga anak. Lebar anak-anak itu dapat diatur dalam tata letak XML, melalui cara apa pun yang diinginkan - Saya menunjukkan menggunakan bobot, tetapi Anda dapat memiliki lebar tertentu yang ditetapkan oleh sumber daya dimensi atau apa pun. Anak ketiga - Fragmen C dalam pertanyaan - harus memiliki lebar nol.Namun, pada saat runtime, tidak peduli bagaimana Anda awalnya mengatur lebar, manajemen lebar diambil alih
ThreePaneLayout
saat pertama kali Anda gunakanhideLeft()
untuk beralih dari menampilkan apa yang disebut pertanyaan sebagai Fragmen A dan B ke Fragmen B dan C. Dalam terminologiThreePaneLayout
- yang tidak memiliki hubungan khusus untuk fragmen - tiga potonganleft
,middle
danright
. Pada saat Anda meneleponhideLeft()
, kami merekam ukuranleft
danmiddle
dan nol bobot apa pun yang digunakan pada salah satu dari ketiganya, sehingga kami dapat sepenuhnya mengontrol ukuran. Pada titik waktuhideLeft()
, kami mengatur ukuranright
menjadi ukuran aslimiddle
.Animasi ada dua:
ViewPropertyAnimator
untuk melakukan terjemahan dari tiga widget ke kiri dengan lebarleft
, menggunakan lapisan perangkat kerasObjectAnimator
properti pseudo-custommiddleWidth
untuk mengubahmiddle
lebar dari apa pun yang dimulai dengan lebar aslileft
(Ada kemungkinan bahwa itu adalah ide yang lebih baik untuk menggunakan
AnimatorSet
danObjectAnimators
untuk semua ini, meskipun ini bekerja untuk saat ini)(Mungkin juga bahwa
middleWidth
ObjectAnimator
meniadakan nilai lapisan perangkat keras, karena itu memerlukan pembatalan yang cukup berkelanjutan)(itu adalah pasti mungkin bahwa saya masih memiliki kesenjangan dalam pemahaman animasi saya, dan yang saya suka pernyataan kurung)
Efek bersihnya adalah
left
slide dari layar,middle
slide ke posisi asli dan ukuranleft
, danright
diterjemahkan tepat di belakangmiddle
.showLeft()
hanya membalikkan proses, dengan campuran animator yang sama, hanya dengan arah terbalik.Aktivitas ini menggunakan a
ThreePaneLayout
untuk menampung sepasangListFragment
widget dan aButton
. Memilih sesuatu di fragmen kiri menambahkan (atau memperbarui konten) fragmen tengah. Memilih sesuatu di fragmen tengah menetapkan keteranganButton
, ditambah dijalankanhideLeft()
padaThreePaneLayout
. Menekan KEMBALI, jika kita menyembunyikan sisi kiri, akan mengeksekusishowLeft()
; jika tidak, KEMBALI keluar dari aktivitas. Karena ini tidak digunakanFragmentTransactions
untuk memengaruhi animasi, kami terjebak mengelola "back stack" itu sendiri.Proyek yang ditautkan ke atas menggunakan fragmen asli dan kerangka animator asli. Saya memiliki versi lain dari proyek yang sama yang menggunakan backport fragmen Dukungan Android dan NineOldAndroids untuk animasi:
https://github.com/commonsguy/cw-omnibus/tree/master/Animation/ThreePaneBC
Backport berfungsi dengan baik pada Kindle Fire generasi pertama, meskipun animasinya sedikit tersentak mengingat spesifikasi perangkat keras yang lebih rendah dan kurangnya dukungan akselerasi perangkat keras. Kedua implementasi tampak mulus pada Nexus 7 dan tablet generasi sekarang lainnya.
Saya tentu saja terbuka untuk ide-ide bagaimana meningkatkan solusi ini, atau solusi lain yang menawarkan keuntungan yang jelas atas apa yang saya lakukan di sini (atau apa yang digunakan @weakwire).
Sekali lagi terima kasih kepada semua orang yang telah berkontribusi!
sumber
ListView
dan menekan tombol kembali dengan cepat dan berulang-ulang maka seluruh Tata Letak melayang ke kanan. Itu mulai menunjukkan kolom ruang ekstra di sebelah kiri. Perilaku ini diperkenalkan karena saya tidak akan membiarkan animasi pertama (dimulai dengan mengetuk di tengahListView
) menyelesaikan dan menekan tombol kembali. Aku tetap dengan menggantitranslationXBy
dengantranslationX
ditranslateWidgets
metode dantranslateWidgets(leftWidth, left, middle, right);
dengantranslateWidgets(0, left, middle, right);
dishowLeft()
metode.requestLayout();
denganmiddle.requestLayout();
disetMiddleWidth(int value);
metode. Ini mungkin tidak mempengaruhi kinerja karena saya kira GPU masih akan melakukan pass tata letak penuh, ada komentar?Kami membangun perpustakaan yang disebut PanesLibrary yang memecahkan masalah ini. Ini bahkan lebih fleksibel daripada apa yang ditawarkan sebelumnya karena:
Anda dapat memeriksanya di sini: https://github.com/Mapsaurus/Android-PanesLibrary
Berikut ini demo: http://www.youtube.com/watch?v=UA-lAGVXoLU&feature=youtu.be
Ini pada dasarnya memungkinkan Anda untuk dengan mudah menambahkan sejumlah panel berukuran dinamis dan melampirkan fragmen ke panel itu. Semoga bermanfaat! :)
sumber
Membangun salah satu contoh yang Anda tautkan ( http://android.amberfog.com/?p=758 ), bagaimana dengan menjiwai
layout_weight
properti? Dengan cara ini, Anda dapat menganimasikan perubahan berat dari 3 fragmen bersama, DAN Anda mendapatkan bonus bahwa mereka semua meluncur bersama dengan baik:Mulailah dengan tata letak yang sederhana. Karena kita akan menghidupkan
layout_weight
, kita perluLinearLayout
sebagai tampilan root untuk 3 panel .:Kemudian kelas demo:
Juga contoh ini tidak menggunakan FragmentTransactions untuk mencapai animasi (lebih tepatnya, ia menganimasikan pandangan fragmen yang dilampirkan), jadi Anda perlu melakukan semua transaksi backstack / fragmen sendiri, tetapi dibandingkan dengan upaya membuat animasi berfungsi baik, ini sepertinya bukan trade-off yang buruk :)
Video beresolusi rendah yang mengerikan sedang beraksi: http://youtu.be/Zm517j3bFCo
sumber
TextView
denganwrap_content
merentangkan dirinya secara vertikal saat animasi berlangsung). Namun, mungkin yang menggerakkan bobot adalah bagaimana mereka mengubah ukuran apa yang saya sebut sebagai Fragment B. Terima kasih!Ini tidak menggunakan fragmen .... Ini tata letak khusus untuk 3 anak. Ketika Anda mengklik pesan, Anda mengimbangi 3 anak menggunakan
offsetLeftAndRight()
dan animator.Di dalamnya
JellyBean
Anda dapat mengaktifkan "Tampilkan batas tata letak" di pengaturan "Opsi Pengembang". Ketika animasi slide selesai, Anda masih dapat melihat bahwa menu kiri masih ada, tetapi di bawah panel tengah.Ini mirip dengan menu aplikasi Cyril Mottier Fly-in , tetapi dengan 3 elemen, bukan 2.
Selain itu,
ViewPager
anak-anak ketiga adalah indikasi lain dari perilaku ini:ViewPager
biasanya menggunakan Fragmen (saya tahu mereka tidak harus melakukannya, tetapi saya belum pernah melihat implementasi yang lainFragment
), dan karena Anda tidak dapat menggunakanFragments
di dalam yang lainFragment
3 anak-anak mungkin bukan fragmen ....sumber
TranslateAnimation
, meskipun saya yakin ada cara menggunakan animator untuk mencapai tujuan yang sama. Saya harus menjalankan beberapa eksperimen tentang ini. Terima kasih!Saat ini saya mencoba melakukan sesuatu seperti itu, kecuali skala Fragment B untuk mengambil ruang yang tersedia dan bahwa 3 panel dapat dibuka pada saat yang sama jika ada cukup ruang. Ini solusi saya sejauh ini, tapi saya tidak yakin apakah saya akan tetap menggunakannya. Saya harap seseorang akan memberikan jawaban yang menunjukkan The Right Way.
Alih-alih menggunakan LinearLayout dan menjiwai bobot, saya menggunakan RelativeLayout dan menghidupkan margin. Saya tidak yakin itu cara terbaik karena memerlukan panggilan ke requestLayout () di setiap pembaruan. Ini lancar di semua perangkat saya.
Jadi, saya menghidupkan tata letak, saya tidak menggunakan fragmen transaksi. Saya menangani tombol kembali secara manual untuk menutup fragmen C jika terbuka.
FragmentB menggunakan layout_toLeftOf / ToRightOf agar tetap sejajar dengan fragmen A dan C.
Ketika aplikasi saya memicu suatu acara untuk menampilkan fragmen C, saya geser masuk fragmen C, dan saya geser keluar fragmen A pada saat yang sama. (2 animasi terpisah). Sebaliknya, ketika Fragment A terbuka, saya menutup C pada saat yang sama.
Dalam mode potret atau pada layar yang lebih kecil, saya menggunakan tata letak yang sedikit berbeda dan geser Fragment C di atas layar.
Untuk menggunakan persentase untuk lebar Fragmen A dan C, saya pikir Anda harus menghitungnya pada waktu berjalan ... (?)
Berikut ini tata letak aktivitas:
Animasi untuk menggeser masuk atau keluar FragmentC:
sumber