UIView.animate(): animaties met UIKit

Een view met animatie

In dit artikel bespreken we UIView.animate(), een methode waarmee je allerlei animaties kunt laten uitvoeren.

UIKit is gebouwd op een aantal krachtige frameworks. Het Core Graphics-framework speelt een grote rol maar voor animaties is een ander framework verantwoordelijk: Core Animation.

De UIView-class beschikt, dankzij Core Graphics en Core Animation, over ingebouwde animatie-mogelijkheden. Hierdoor is het toevoegen van animatie aan views heel eenvoudig: het is vaak een kwestie van maar een paar regels programmacode.

Een voorbeeld: de UIView.animate()-methode

Een voorbeeld zie je in de volgende app. Deze app zet een button op het scherm; zodra de gebruiker op de button tapt, wordt deze tijdelijk groter en draait hij om z’n as.

UIView.animate() in actie

Je kunt deze app op twee manieren maken. In het voorbeeld hieronder gebeurt alles in programmacode: de button wordt door de .viewDidLoad()-methode aan de hoofd-view toegevoegd. Als je liever het Storyboard wilt gebruiken, hoef je de .viewDidLoad()-methode niet te schrijven. Maak de button dan in het Storyboard, waarna je een IBOutlet (met de naam button) toevoegt. Koppel bovendien een IBAction met de naam animeer aan de button, zodat de .animeer()-methode wordt aangeroepen wanneer de gebruiker op de button tapt of klikt.

Wat je natuurlijk nog wel moet schrijven, is de programmacode voor de .animeer()-methode: die staat onderaan in de nu volgende programmacode.

Een app met een button

De magie vindt plaats in de .animeer()-methode:

Deze methode wordt aangeroepen zodra je op de button tapt. Als je voor de eerste keer een UIView-animatie ziet: niet schrikken! Het lijkt allemaal behoorlijk complex, maar voor nu hoef je alleen maar te letten op de feitelijke inhoud van de .animeer()-methode: er staat één andere methode in, met de naam UIView.animiate(withDuration:animations:).

Deze speciale class-methode van UIView zorgt voor de animatie: hij geeft alles wat geanimeerd kan worden, door aan het Core Animation-framework. Daarna zorgt Core Animation ervoor dat de animatie wordt afgespeeld.

De basisversie van UIView.animate(with:duration): tijdsduur en closure

De eenvoudigste vorm van de .animate(withDuration:animations)-methode ziet er als volgt uit:

UIView.animate(withDuration: NSTimeInterval, animations: () -> void)

Deze methode verwacht twee argumenten: de tijdsduur van de animatie en een closure. De closure bevat de instructies voor Core Animation, zodat Core Animation de animatie kan afspelen.

Een closure is niets anders dan een naamloze functie. Ze worden uitgebreid behandeld in het eBook Apps bouwen met Swift – Programmeren met Swift.

Let op: alle regels in de closure worden meteen uitgevoerd. De feitelijke animatie wordt, terwijl de closure alweer klaar is, verder door Core Animation afgehandeld.

Als je een variabele of property wijzigt in een closure die door de .animate(withDuration:animations:)-methode wordt uitgevoerd, vindt die wijziging meteen plaats. Het effect van die wijziging wordt echter pas later zichtbaar: daarvoor zorgt het Core Animation-framework.

Closures zijn niets anders dan functies zonder naam; in plaats van een closure kun je als argument dus ook een functie doorgeven. Een voorbeeld daarvan zie je hieronder.

Start de app nu opnieuw en raak de button aan. De achtergrond van de button wordt nu langzaam rood: de animatie duurt precies twee seconden. De volgende gebeurtenissen vinden plaats meteen nadat de button is aangeraakt:

  1. De .animeer()-methode wordt aangeroepen.
  2. De UIView.animate(withDuration:animations)-methode wordt aangeroepen.
  3. UIView.animate(withDuration:animations) voert de .veranderKleur()-methode uit. De huidige achtergrondkleur (wit) wordt aan Core Animation doorgegeven: dit is de kleur waarmee de animatie begint.
  4. De .backgroundColor-property krijgt meteen de waarde ‘rood’.
  5. UIView.animate(withDuration:animations:)) is nu klaar en wordt beëindigd.
  6. .animeer() is nu klaar en wordt beëindigd.
  7. Core Animation zorgt voor de animatie: op het scherm verandert de achtergrondkleur langzaam van wit naar rood.

Core Animation houdt de properties waarmee het bezig is, goed in de gaten. Als gedurende de animatie .backgroundColor weer wordt gewijzigd, bijvoorbeeld in groen, zal Core Animation de animatie voortzetten, maar nu met groen als eindkleur. Apple raadt echter af om properties te wijzigen waarmee Core Animation nog aan het werk is; doe dat dus pas nadat de animatie is afgelopen.

Een paar dingen zijn belangrijk om te weten als je met view-animatie werkt:

  • Slechts zes properties van een UIViewkunnen door Core Animation worden geanimeerd: .frame, .center, .bounds, .backgroundColor, .alpha en .transform.
  • Ook als een property-wijziging via Core Animation wordt geanimeerd, krijgt de property zelf meteen de nieuwe waarde. Je ziet weliswaar een kleur veranderen, maar de achtergrondkleur-property heeft zijn nieuwe waarde al! Core Animation speelt als het ware een ‘film af’. Wat je ziet, is dus niet de werkelijkheid: eventuele properties zijn namelijk al gewijzigd, ook als dat op het scherm nog niet zichtbaar is.
  • De feitelijke animatie wordt door Core Animation verzorgd. Die animatie wordt afgespeeld terwijl de UIView.animate(withDuration:animations))-methode allang is afgerond.
  • De tijd die als eerste argument aan UIView.animate(withDuration:animations) wordt doorgegeven, is bestemd voor Core Animation. Het is de lengte van de ‘film die Core Animation afspeelt’. Het is dus niet zo dat UIView.animate(withDuration:animations:) wacht totdat die tijd is verstreken.
  • Wanneer Core Animation een animatie afspeelt op basis van een bepaalde property, blijft het die property in de gaten houden. Als de waarde van die property verandert terwijl de animatie nog aan de gang is, neemt Core Animation die waarde over en gebruikt hem in de rest van de animatie. Dit kan echter problemen opleveren; vandaar dat wordt aangeraden om properties die bij een nog afspelende animatie horen, niet te wijzigen – doe dat pas als de animatie is afgelopen.

Kijk, met deze dingen in je achterhoofd, eens naar de volgende versie van de .veranderKleur()-methode:

Je ziet dat de .backgroundColor-property twee keer wordt aangepast. Omdat dit ook als onderdeel van een UIView.animate(withDuration:animations)-methode gebeurt, is Core Animation hierbij betrokken.

De achtergrondkleur van de button is, vlak nadat de app is gestart, wit. Die kleur zal dus door Core Animation als ‘startkleur’ worden gebruikt.

Als ‘eindkleur’ zal Core Animation in eerste instantie groen nemen: de .veranderKleur()-methode maakt de .backgroundColor-property immers groen. Maar… meteen daarna, nadat UIView.animate(withDuration:animations) is afgehandeld, wordt de .backgroundColor-property rood. Core Animation ziet dit en gebruikt rood als de nieuwe ‘eindkleur’ voor de animatie. De feitelijke animatie zal dus van wit naar rood zijn.