Acest articol se concentrează pe utilizarea animațiilor CA în iOS pentru a realiza animații fluide.

În primele zile de lucru cu iOS, eram foarte nervos ori de câte ori un designer venea la mine și îmi cerea niște animații în aplicația la care lucrau.

Cum CAAnimation m a ajutat sa cuceresc frica mea de a
Craaaaap

Obișnuiam să cred că este ușor să vin cu designul pentru animații – dar implementarea acestuia, pe de altă parte, a fost o sarcină foarte dificilă.

Aș primi ajutor de la Google, StackOverflow și colegii mei pentru implementare.
În timpul procesului am dezvoltat o fobie a animațiilor și am încercat întotdeauna să le evit. Dar totul s-a schimbat într-o zi.

Găsirea CAAnimation

Odată, a trebuit să anim o secvență de imagini într-o vizualizare. Deci, care a fost primul meu pas? Evident, StackOverflow!

ad-banner

Primul link a primit codul.

let image_1 = UIImage(named: "image-1")!
let image_2 = UIImage(named: "image-2")!
let image_3 = UIImage(named: "image-3")!
let images = [image_1, image_2, image_3]
let animatedImage = UIImage.animatedImage(with: images, duration: 2.0)
imageView.image = animatedImage
1611271266 112 Cum CAAnimation m a ajutat sa cuceresc frica mea de a

Pare destul de simplu, nu? Dacă ar fi atât de simplu, nu aș scrie acest articol.

Aceasta este animația necesară:

1611271267 822 Cum CAAnimation m a ajutat sa cuceresc frica mea de a
Obiectiv final

Și așa cum a devenit probabil clar, nu eram nicăieri aproape de ea. Eram blocat. Cum trebuia să fac atât de multe personalizări în animația respectivă și să le sincronizez pe toate?

Apoi colegul meu mi-a spus să încerc CAAnimație. Am citit despre asta și l-am încercat într-un exemplu de proiect. Spre uimirea mea, a fost cu adevărat puternic și ușor de utilizat.

Ce este Core Animation?

Core Animation vă ajută să executați mai multe animații cu o utilizare aproape nulă a procesorului.
Vă oferă o rată ridicată a cadrelor și multe personalizări pe care le puteți utiliza cu foarte puțin cod.

Puteți găsi mai multe detalii în documente aici: https://developer.apple.com/documentation/quartzcore

Am reușit să realizez o implementare de bază în câteva ore:

func addAnimation(firstImageView: UIImageView, secondImageView: UIImageView) {
        let basicAnimation1 = getBasicAnimation(withInitialPostion: centerPosition, finalPos: finalPosition)
        firstImageView.layer.add(basicAnimation1, forKey: "position")        
        let basicAnimation2 = self.getBasicAnimation(withInitialPostion: self.initalPosition, finalPos: self.centerPosition)
        secondImageView.layer.add(basicAnimation2, forKey: "position")
        self.addNextImage(forImageView: firstImageView)
    }
    func getBasicAnimation(withInitialPostion initialPos: CGPoint, finalPos: CGPoint) -> CABasicAnimation {
        let basicAnimation = CABasicAnimation(keyPath: "position")
        basicAnimation.fromValue = NSValue(cgPoint: initialPos)
        basicAnimation.toValue = NSValue(cgPoint: finalPos)
        basicAnimation.duration = 1
        basicAnimation.isRemovedOnCompletion = false
        basicAnimation.fillMode = CAMediaTimingFillMode.forwards
        basicAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
        return basicAnimation
    }
1611271268 312 Cum CAAnimation m a ajutat sa cuceresc frica mea de a
CA animație de bază

Pentru această implementare, am folosit CABasicAnimation.

CABasicAnimation class vă ajută să animați o proprietate de strat (care poate fi culoarea de fundal, opacitate, poziție, scară) între două valori. Trebuie doar să dai o valoare de început și de sfârșit, iar restul va fi îngrijit. Animația începe imediat în următoarea buclă de rulare, așa cum este descris mai complet aici.

Acum, înapoi la problema noastră.

Pentru a implementa acest lucru, am luat două vizualizări de imagini și le-am adăugat două imagini separate. Apoi am continuat să-i anim pe unul după altul folosind CAAnimation.

Puteți găsi codul sursă aici.

Dacă examinați ultimul gif, veți vedea că ceva este oprit. Înainte ca prima imagine a unei cutii cadou să nu mai fie vizibilă, căștile clipesc scurt și apoi imaginea se deplasează în sus.

De ce se întâmplă asta?

Acest lucru se datorează faptului că de îndată ce adăugăm animația la vizualizarea imaginii, adăugăm următoarea imagine la acea vizualizare (liniile cu numărul 5 și 6):

private func addAnimation(firstImageView: UIImageView, secondImageView: UIImageView) {
    let basicAnimation1 = getBasicAnimation(withInitialPostion: centerPosition, finalPos: finalPosition)
    firstImageView.layer.add(basicAnimation1, forKey: "position")    
    let basicAnimation2 = self.getBasicAnimation(withInitialPostion: self.initalPosition, finalPos: self.centerPosition)
    secondImageView.layer.add(basicAnimation2, forKey: "position")
    self.addNextImage(forImageView: firstImageView)
}

Aici ne luptăm cu problema cum să sincronizăm ambele imagini în animație. Dar există întotdeauna o soluție cu CAAnimation.

Tranzacții CA.

Tranzacțiile CA ne ajută să sincronizăm mai multe animații împreună. Se asigură că toate animațiile pe care le-am combinat împreună încep toate în același timp.

De asemenea, puteți oferi un bloc de finalizare animațiilor dvs., care va fi executat atunci când toate animațiile dintr-un singur pachet sunt finalizate.

Puteți citi mai multe despre asta aici.

private func addAnimation(firstImageView: UIImageView, secondImageView: UIImageView) {
    CATransaction.begin()
    CATransaction.setCompletionBlock {
        self.addNextImage(forImageView: firstImageView)
    }
    let basicAnimation1 = getBasicAnimation(withInitialPostion: centerPosition, finalPos: finalPosition)
    firstImageView.layer.add(basicAnimation1, forKey: "position")
    CATransaction.commit()
    
    let basicAnimation2 = self.getBasicAnimation(withInitialPostion: self.initalPosition, finalPos: self.centerPosition)
    secondImageView.layer.add(basicAnimation2, forKey: "position")
}

Începi prin a scrie CATransaction.begin(). Apoi, scrieți toate animațiile pe care doriți să le faceți sincronizate. În cele din urmă, sunați CATransaction.commit() care va începe animația din bloc.

Să vedem cum arată animația noastră acum:

1611271269 745 Cum CAAnimation m a ajutat sa cuceresc frica mea de a
Tranzacție CA.

Un ultim lucru pe care trebuia să-l fac a fost să adaug efectul Spring la animație. Din fericire, CAAnimation a avut și o soluție pentru acest lucru.

Animație CA Spring

CA Spring Animation, atunci când este adăugat la un strat, îi dă un efect asemănător arcului, astfel încât pare să fie tras spre o țintă de un arc.

Cu cât stratul este mai departe de țintă, cu atât este mai mare accelerația spre acesta.

Permite controlul asupra atributelor bazate fizic, cum ar fi amortizarea și rigiditatea arcului. – Documente

Puteți citi mai multe despre aceasta din documentația Apple: https://developer.apple.com/documentation/quartzcore/caspringanimation

Să-l implementăm în codul nostru existent:

private func getSpringAnimation(withInitialPostion initialPos: CGPoint, finalPos: CGPoint) -> CASpringAnimation {
    let basicAnimation = CASpringAnimation(keyPath: "position")
    basicAnimation.fromValue = NSValue(cgPoint: initialPos)
    basicAnimation.toValue = NSValue(cgPoint: finalPos)
    basicAnimation.duration = basicAnimation.settlingDuration
    basicAnimation.damping = 14
    basicAnimation.initialVelocity = 5
    basicAnimation.isRemovedOnCompletion = false
    basicAnimation.fillMode = CAMediaTimingFillMode.forwards
    return basicAnimation
}
1611271270 239 Cum CAAnimation m a ajutat sa cuceresc frica mea de a
Voila

Munca mea este terminată aici.

În rezumat, iată câteva dintre avantajele utilizării CA Animations:

  • Sunt ușor de utilizat și de implementat
  • Există o mulțime de personalizări disponibile
  • Este posibil să sincronizați mai multe animații
  • Aproape zero utilizare CPU

Acestea sunt doar câteva dintre avantaje. Posibilitățile sunt nelimitate.

Acum, ori de câte ori vin cerințele pentru animație, mă simt încrezător în proiectarea și implementarea lor. Și sper să vă simțiți la fel și după ce ați citit acest lucru.
Nu ezitați să lăsați orice sugestie sau feedback.