Hvordan CAAnimation hjalp mig med at overvinde min frygt for at skabe animationer

Denne artikel fokuserer på at bruge CA-animationer i iOS til at lave glatte animationer.

I løbet af de første dage, jeg arbejdede med iOS, blev jeg meget nervøs, hver gang en designer kom hen til mig og bad om animation i den app, de arbejdede med.

Jeg troede, det var let at komme med designet til animationer - men på den anden side at implementere det var en meget vanskelig opgave.

Jeg ville få hjælp fra Google, StackOverflow og mine jævnaldrende til implementeringen.

Under processen udviklede jeg en fobi for animationer og forsøgte altid at undgå dem. Men det hele ændrede sig en dag.

Find CAA-animation

En gang var jeg nødt til at animere en sekvens af billeder i en visning. Så hvad var mit første skridt? Naturligvis StackOverflow!

Det første link fik koden.

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

Virker ret ligetil, ikke? Hvis det var så simpelt, ville jeg ikke skrive denne artikel.

Dette er den krævede animation:

Og som det sandsynligvis er blevet klart, var jeg ikke tæt på det. Jeg sad fast. Hvordan skulle jeg udføre så mange tilpasninger i den animation og synkronisere dem alle?

Derefter bad min kollega mig om at prøve CAAnimation. Jeg læste om det og prøvede det på et prøveprojekt. Til min forbløffelse var det virkelig stærkt og let at bruge.

Hvad er Core Animation?

Core Animation hjælper dig med at udføre flere animationer med næsten nul CPU-brug.

Det giver dig høj billedhastighed og mange tilpasninger, som du kan bruge med meget lidt kode.

Du kan finde flere detaljer i dokumenterne her: //developer.apple.com/documentation/quartzcore

Jeg var i stand til at udføre en grundlæggende implementering på få timer:

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 }

Til denne implementering brugte jeg CABasicAnimation .

Den CABasicAnimation klasse hjælper dig animere et lag ejendom (som kan være baggrundsfarve, opacitet, placering, skala) mellem to værdier. Du skal bare give en start- og slutværdi, og resten bliver taget hånd om. Animationen begynder straks i den næste kørsløjfe som beskrevet mere detaljeret her.

Nu tilbage til vores problem.

For at implementere dette tog jeg to billedvisninger og tilføjede to separate billeder til dem. Så fortsatte jeg med at animere dem efter hinanden ved hjælp af CAAnimation.

Du kan finde kildekoden her.

Hvis du undersøger den sidste gif, vil du se, at noget er slukket. Før det første billede af en gaveæske går ud af syne, blinker hovedtelefonerne kort, og derefter flytter billedet op.

Hvorfor sker dette?

Det er fordi, så snart vi tilføjer animationen til billedvisningen, tilføjer vi det næste billede til den visning (linie nummer 5 og 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) }

Her kæmper vi med spørgsmålet om, hvordan man synkroniserer begge billeder i animationen. Men der er altid en løsning med CAAnimation.

CA-transaktioner

CA-transaktioner hjælper os med at synkronisere flere animationer sammen. Det sørger for, at alle de animationer, som vi er samlet sammen, starter på samme tid.

Du kan også give en færdiggørelsesblok til dine animationer, som udføres, når alle dine animationer i en pakke er afsluttet.

Du kan læse mere om det her.

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") }

Du starter med at skrive CATransaction.begin(). Skriv derefter alle dine animationer, som du vil synkronisere. Endelig skal du ringe, CATransaction.commit()som starter animationen i blokken.

Lad os se, hvordan vores animation ser ud nu:

En sidste ting, jeg havde brug for, var at tilføje Spring-effekten til animationen. Heldigvis havde CAAnimation også en løsning på dette.

CA Spring Animation

CA Spring Animation giver, når det føjes til et lag, en fjederlignende effekt til det, så det ser ud til at blive trukket mod et mål af en fjeder.

Jo længere laget er fra målet, jo større er accelerationen mod det.

Det giver mulighed for kontrol over fysisk baserede egenskaber såsom fjederdæmpning og stivhed. - Dokumenter

Du kan læse mere om det fra Apple-dokumentation: //developer.apple.com/documentation/quartzcore/caspringanimation

Lad os implementere det i vores eksisterende kode:

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 }

Mit arbejde er udført her.

Sammenfattende er her nogle af fordelene ved at bruge CA-animationer:

  • De er nemme at bruge og implementere
  • Der er mange tilpasninger til rådighed
  • Det er muligt at synkronisere flere animationer
  • Næsten nul CPU-brug

Disse er blot nogle få af fordelene. Mulighederne er uendelige.

Nu, når der stilles krav til animation, føler jeg mig sikker på at designe og implementere dem. Og jeg håber, du også har det på samme måde efter at have læst dette.

Du er velkommen til at efterlade forslag eller feedback.