
Ada praktik yang baik untuk membuat aplikasi Anda indah dan hidup, dan saat ini ada banyak alat dan cara untuk mencapai ini. Salah satunya adalah Shared Element Transition.
Dalam artikel ini saya akan membahas beberapa kesalahan yang menghabiskan banyak waktu; Saya akan menunjukkan cara untuk menghindarinya jika Anda memutuskan untuk menerapkan transisi semacam ini dengan Fragmen pada aplikasi.
Mulai
Sebelum membuat animasi, saya sudah membaca puluhan artikel tetapi kebanyakan tentang Transisi Aktivitas. Namun, saya menemukan yang sangat bagus tentang Fragmen dan saya ingin memberikan sedikit rekap tentang cara membuat Shared Element Transition.
Berikut langkah-langkah utama untuk membuat animasi:
- Aktifkan
setReorderingAllowed(true)
. Hal ini memungkinkan untuk menyusun ulang metode panggilan siklus hidup dan animasi Anda akan ditampilkan dengan benar. - Panggil
addSharedElement()
dan tambahkan tampilan yang akan dibagikan di antara layar - Tambahkan
android:transitionName
unik android:transitionName
pada setiap tampilan dalam transisi - Tambahkan
sharedElementEnterTransition/sharedElementReturnTransition
dalam fragmen tujuan. Secara opsional: untuk efek yang lebih baik, kita juga dapat mengatur enterTransition/exitTransition
. - Tambahkan
postponeEnterTransition/startPostponedEnterTransition
untuk menentukan saat ketika data dimuat dan UI siap ditarik
Sepertinya itu cukup untuk membangun animasi dan membuat desainer dan pengguna Anda bahagia. TAPI selalu ada beberapa kecelakaan. Mari kita lihat apa yang akan kita miliki jika kita mengambil langkah-langkah yang tercantum di atas:
Bukan itu yang kami harapkan. Mari kita cari tahu.
Kesalahan # 1. Nama transisi statis (setengah hari terbuang)
Seperti yang saya katakan sebelumnya, Tampilan kita harus memiliki nama transisi yang unik - jika tidak kerangka kerja transisi tidak akan dapat mengenali Tampilan mana yang mengambil bagian dengan transisi dan akan membuatnya tanpa mereka. Jadi di mana masalahnya?
Masalahnya adalah RecyclerView. Itu dia.
Jika ada RecyclerView dan tampilan animating adalah bagian dari item RecyclerView, Anda harus membuat dan mengatur nama
transitionName
secara dinamis (lupakan tentang XML). Selain itu, Anda harus melakukannya di kedua fragmen bahkan jika yang kedua tidak memiliki RecyclerView.
Jadi perbaikannya adalah:
val transitionNameImage = context.getString(R.string.transition_image, title)
Anda mungkin memperhatikan bahwa saya menempatkan "judul" sebagai argumen untuk mendapatkan nama yang unik. Lebih baik menggunakan model domain daripada, misalnya, posisi item di layar, karena tidak perlu meneruskan nama-nama ini sebagai argumen ke Bundle dan parsing mereka dari Fragmen kedua.
Kesalahan # 2. Tidak mempertimbangkan fragmen orang tua (1,5 hari terbuang)
Saya tahu, Anda mungkin bertanya, "Bagaimana bisa?" Tetapi ketika saya membaca artikel tentang animasi bersama, tidak ada yang mempertimbangkan contoh dalam hierarki fragmen yang kompleks. Karena itulah terkadang Anda mungkin tidak memperhatikannya.
Jadi, fragmen pertama saya adalah anak dari wadah fragmen dan tidak mengherankan bahwa
postponeEnterTransition()/startPostponedEnterTransition()
tidak berpengaruh.
Ini dia override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) parentFragment?.also { parentFragment -> NewsTransitioner.setupFirstFragment(parentFragment) parentFragment.postponeEnterTransition() }
Yang perlu Anda lakukan di sini adalah memanggil metode ini dari fragmen induk.
Kesalahan # 3. Underestimating Glide (2 hari terbuang)
"Oke, saya sudah belajar bagaimana melakukan transisi bersama, kapan harus memanggil metode yang diperlukan mengenai siklus hidup dan pemuatan. Kali ini akan berhasil! "
Ya saya salah. Ini mungkin kesalahan paling sulit yang pernah saya hadapi. Mari kita lihat apa yang kita miliki sejauh ini:
Anda mungkin melihat ada kesalahan aneh dengan memasuki transisi. Ketika dimulai, gambar sudah berubah matriks dan kemudian hanya pindah ke posisi akhir.
Saya tidak ingin menggambarkan keseluruhan penyelidikan di sini. Singkat cerita, saya beruntung menemukan
artikel yang bagus .
Di mana saya menemukan solusi. Ini dia:
“Kami memiliki kesalahan ini karena Glide mencoba mengoptimalkan pemuatan gambar. Secara default, Glide mengubah ukuran dan memangkas gambar agar sesuai dengan tampilan target. ”
Untuk memperbaikinya, saya menambahkan, tidak ada lelucon, satu baris kode seperti ini untuk inisialisasi rantai Glide:
Glide .with(target) .load(url) .apply( RequestOptions().dontTransform()
Jadi, Anda harus menonaktifkan transformasi Glide pada gambar jika mereka terlibat dalam transisi bersama.
Kesalahan # 4. Mengelola postPostponeTransition () dengan salah
Jujur, itu bukan kesalahan tapi saya pikir itu akan bagus untuk disebutkan.
Ketika datang untuk mengelola
postPostponeTransition()
dan
startPostponedEnterTransition()
, Anda harus memilih saat yang tepat. Saatnya adalah ketika UI sudah ditarik.
Ada dua poin utama yang harus kita ketahui sebelum memanggil metode:
- di satu sisi, ketika gambar dengan transisi dimuat dan siap
- di sisi lain, hierarki pandangan diukur dan ditata
Untuk gambar biasanya kami menggunakan Glide dan memiliki pendengar mewah:
RequestListener<Drawable> { override fun onLoadFailed( e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean ): Boolean { startPostponedEnterTransition() return false } override fun onResourceReady( resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean ): Boolean { startPostponedEnterTransition() return false } }
Perhatikan bahwa kami memanggil
startPostponedEnterTransition()
dalam kedua kasus: sukses dan kesalahan. Ini penting karena jika kami tidak membuatnya aplikasi Anda akan membeku.
Dalam kasus ketika transisi datang tanpa gambar, Anda dapat menggunakan metode ekstensi
doOnPreDraw()
dari ktx pada tata letak root dan lakukan
startPostponedEnterTransition()
di sana.
BONUS : Berbicara tentang RecyclerView, tidak cukup hanya menambahkan pendengar untuk gambar. Kita harus mempertahankan posisi item RecyclerView tempat transisi dimulai. Ketika pengguna kembali ke layar sebelumnya, kita harus membandingkan posisi yang dimuat gambar dengan posisi yang dipertahankan pada pendengar dan memulai transisi hanya ketika mereka cocok.
Menyatukan semua
Dalam artikel ini, saya telah menunjukkan beberapa gotcha yang mungkin Anda hadapi mengimplementasikan transisi bersama dengan fragmen dan cara untuk mengatasinya.
Secara singkat, ini mereka:
- Perlu diingat hierarki fragmen (jangan lupa tentang fragmen induk)
- Dalam hal RecyclerView, selalu buat nama transisi secara dinamis (sumber + tujuan)
- Nonaktifkan setiap transformasi Glide
- Lakukan panggilan
postPostponeTransition()
dan startPostponedEnterTransition()
dengan benar terkait logika Anda.
Terima kasih telah membaca dan melihat Anda lain kali!
PS Jika Anda bertanya-tanya bagaimana cara menghidupkan sudut gambar, di
sini kodenya , tambahkan saja transisi animasi yang dibagikan.
Contoh fragment.sharedElementEnterTransition = TransitionSet().apply { addTransition(ChangeImageTransform()) addTransition(ChangeBounds()) addTransition(ChangeTransform()) addTransition(ChangeOutlineRadiusTransition(animationRadiusData.startRadius, animationRadiusData.endRadius) ) }