Saya memiliki masalah di mana saya memiliki serangkaian urutan CATransition / CAAnimation yang tumpang tindih, yang semuanya saya perlukan untuk melakukan operasi kustom saat animasi berhenti, tetapi saya hanya menginginkan satu penangan delegasi untuk animationDidStop.
Namun, saya punya masalah, sepertinya tidak ada cara untuk mengidentifikasi secara unik setiap CATransition / CAAnimation dalam delegasi animationDidStop.
Saya memecahkan masalah ini melalui sistem kunci / nilai yang diekspos sebagai bagian dari CAAnimation.
Saat Anda memulai animasi, gunakan metode setValue pada CATransition / CAAnimation untuk menyetel pengenal dan nilai Anda yang akan digunakan saat animationDidStop diaktifkan:
-(void)volumeControlFadeToOrange
{
CATransition* volumeControlAnimation = [CATransition animation];
[volumeControlAnimation setType:kCATransitionFade];
[volumeControlAnimation setSubtype:kCATransitionFromTop];
[volumeControlAnimation setDelegate:self];
[volumeControlLevel setBackgroundImage:[UIImage imageNamed:@"SpecialVolume1.png"] forState:UIControlStateNormal];
volumeControlLevel.enabled = true;
[volumeControlAnimation setDuration:0.7];
[volumeControlAnimation setValue:@"Special1" forKey:@"MyAnimationType"];
[[volumeControlLevel layer] addAnimation:volumeControlAnimation forKey:nil];
}
- (void)throbUp
{
doThrobUp = true;
CATransition *animation = [CATransition animation];
[animation setType:kCATransitionFade];
[animation setSubtype:kCATransitionFromTop];
[animation setDelegate:self];
[hearingAidHalo setBackgroundImage:[UIImage imageNamed:@"m13_grayglow.png"] forState:UIControlStateNormal];
[animation setDuration:2.0];
[animation setValue:@"Throb" forKey:@"MyAnimationType"];
[[hearingAidHalo layer] addAnimation:animation forKey:nil];
}
Dalam delegasi animationDidStop Anda:
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag{
NSString* value = [theAnimation valueForKey:@"MyAnimationType"];
if ([value isEqualToString:@"Throb"])
{
//... Your code here ...
return;
}
if ([value isEqualToString:@"Special1"])
{
//... Your code here ...
return;
}
//Add any future keyed animation operations when the animations are stopped.
}
Aspek lain dari ini adalah memungkinkan Anda untuk mempertahankan status dalam sistem penyandingan nilai kunci alih-alih harus menyimpannya di kelas delegasi Anda. Semakin sedikit kode, semakin baik.
Pastikan untuk memeriksa Referensi Apple tentang Pengodean Pasangan Nilai Kunci .
Apakah ada teknik yang lebih baik untuk identifikasi CAAnimation / CATransition di delegasi animationDidStop?
Terima kasih, --Batgar
sumber
CAAnimation
itudelegate
kuat, jadi Anda mungkin perlu mengaturnyanil
untuk menghindari siklus penahanan!Jawaban:
Teknik Batgar terlalu rumit. Mengapa tidak memanfaatkan parameter forKey di addAnimation? Itu dimaksudkan untuk tujuan ini. Cukup lakukan panggilan ke setValue dan pindahkan string kunci ke panggilan addAnimation. Sebagai contoh:
Kemudian, dalam callback animationDidStop, Anda dapat melakukan sesuatu seperti:
sumber
anim.removedOnCompletion = NO;
agar tetap ada saat-animationDidStop:finished:
dipanggil.Saya baru saja menemukan cara yang lebih baik untuk melakukan kode penyelesaian untuk CAAnimations:
Saya membuat typedef untuk sebuah blok:
Dan kunci yang saya gunakan untuk menambahkan blok ke animasi:
Kemudian, jika saya ingin menjalankan kode penyelesaian animasi setelah CAAnimation selesai, saya menetapkan diri saya sebagai delegasi animasi, dan menambahkan blok kode ke animasi menggunakan setValue: forKey:
Kemudian, saya mengimplementasikan metode animationDidStop: finish:, yang memeriksa blok pada kunci yang ditentukan dan menjalankannya jika ditemukan:
Keunggulan dari pendekatan ini adalah Anda dapat menulis kode pembersihan di tempat yang sama tempat Anda membuat objek animasi. Lebih baik lagi, karena kodenya adalah sebuah blok, ia memiliki akses ke variabel lokal dalam lingkup terlampir yang ditentukannya. Anda tidak perlu repot menyiapkan kamus userInfo atau omong kosong lainnya, dan tidak perlu menulis metode animationDidStop: finish: yang terus berkembang yang menjadi semakin kompleks saat Anda menambahkan berbagai jenis animasi.
Sejujurnya, CAAnimation harus memiliki properti blok penyelesaian yang dibangun di dalamnya, dan dukungan sistem untuk memanggilnya secara otomatis jika ada yang ditentukan. Namun, kode di atas memberi Anda fungsionalitas yang sama dengan hanya beberapa baris kode tambahan.
sumber
theBlock();
dipanggil, dan saya yakin itu disebabkan oleh fakta bahwa cakupan blok dihancurkan.Pendekatan kedua hanya akan berfungsi jika Anda secara eksplisit menyetel animasi Anda agar tidak dihapus saat selesai sebelum menjalankannya:
Jika Anda gagal melakukannya, animasi Anda akan dihapus sebelumnya setelah selesai, dan callback tidak akan menemukannya di kamus.
sumber
Semua jawaban lain terlalu rumit! Mengapa Anda tidak menambahkan kunci Anda sendiri untuk mengidentifikasi animasi?
Solusi ini sangat mudah, yang Anda butuhkan hanyalah menambahkan kunci Anda sendiri ke animasi (animationID dalam contoh ini)
Sisipkan baris ini untuk mengidentifikasi animasi1 :
dan ini untuk mengidentifikasi animasi2 :
Ujilah seperti ini:
Itu tidak memerlukan variabel contoh apa pun :
sumber
[animation valueForKey:@"animationID"]
Untuk membuat eksplisit apa yang tersirat dari atas (dan apa yang membawa saya ke sini setelah beberapa jam yang terbuang): jangan berharap untuk melihat objek animasi asli yang Anda alokasikan kembali kepada Anda oleh
saat animasi selesai, karena
[CALayer addAnimation:forKey:]
membuat salinan animasi Anda.Apa yang dapat Anda andalkan, adalah bahwa nilai kunci yang Anda berikan ke objek animasi Anda masih ada dengan nilai yang setara (tetapi tidak harus setara dengan penunjuk) di objek animasi replika yang diteruskan dengan
animationDidStop:finished:
pesan. Seperti disebutkan di atas, gunakan KVC dan Anda mendapatkan ruang lingkup yang luas untuk menyimpan dan mengambil status.sumber
[animation setValue:@"myanim" forKey:@"name"]
dan Anda bahkan dapat mengatur lapisan yang dianimasikan menggunakan[animation setValue:layer forKey:@"layer"]
. Nilai ini kemudian dapat diambil dalam metode delegasi.valueForKey:
kembalinil
untukku, tahu kenapa?Saya dapat melihat sebagian besar jawaban objc. Saya akan membuat satu untuk 2.3 cepat berdasarkan jawaban terbaik di atas.
Sebagai permulaan, akan sangat baik untuk menyimpan semua kunci tersebut di sebuah private struct sehingga ini adalah tipe yang aman dan mengubahnya di masa depan tidak akan membawa Anda bug yang mengganggu hanya karena Anda lupa mengubahnya di mana-mana dalam kode:
Seperti yang Anda lihat, saya telah mengubah nama variabel / animasi agar lebih jelas. Sekarang atur tombol-tombol ini saat animasi dibuat.
(...)
Lalu akhirnya menangani delegasi saat animasi berhenti
sumber
IMHO menggunakan nilai kunci Apple adalah cara elegan untuk melakukan ini: ini secara khusus dimaksudkan untuk memungkinkan penambahan data spesifik aplikasi ke objek.
Kemungkinan lain yang kurang elegan adalah menyimpan referensi ke objek animasi Anda dan melakukan perbandingan penunjuk untuk mengidentifikasinya.
sumber
Bagi saya untuk memeriksa apakah 2 objek CABasicAnimation adalah animasi yang sama, saya menggunakan fungsi keyPath untuk melakukan persis seperti itu.
if ([animationA keyPath] == [animationB keyPath])
sumber
Saya suka menggunakan
setValue:forKey
: untuk menyimpan referensi tampilan yang saya animasikan, ini lebih aman daripada mencoba mengidentifikasi animasi secara unik berdasarkan ID karena jenis animasi yang sama dapat ditambahkan ke lapisan yang berbeda.Keduanya setara:
dengan yang ini:
dan dalam metode delegasi:
sumber
Xcode 9 Swift 4.0.0 Memperbarui
Anda dapat menggunakan Nilai Kunci untuk menghubungkan animasi yang Anda tambahkan ke animasi yang dikembalikan dalam metode delegasi animationDidStop.
Deklarasikan kamus berisi semua animasi aktif dan penyelesaian terkait:
Saat Anda menambahkan animasi Anda, setel kunci untuk itu:
Dalam animationDidStop, keajaiban terjadi:
sumber