Esecuzione di iOS Animazioni Viste Con UIKit E UIView
- Circa L’Autore
- Animazione A 60FPS
- Core Frameworks
- Animazioni UIKit/UIView
- animation (withDuration: animations: completion)
- animateWithDuration
- UIViewPropertyAnimator
- Che cos’è unframe?
- animateKeyframes
- CoreAnimation
- UIView + Core Animation
- UIKitDynamics
- UIKitDynamicAnimator
- UIKitDynamicBehavior
- Ottimizzazione delle prestazioni
- Core Animation Strumento
- Disegno
- Rasterizzazione
- Avvolgendo
Circa L’Autore
Saravanan è un iOS ingegnere e scrittore a Flexiple e Strumenti Remoti. Ha lavorato con più startup in diversi domini.Più aboutSaravanan↬
- 14 min leggere
- Animazione,iOS,UI,Mobile
- Salvate per la lettura offline
- Condividi su Twitter”, LinkedIn
Sono stato uno sviluppatore iOS per oltre un decennio e raramente ho visto articoli che consolidano tutti i modi possibili per eseguire animazioni in iOS. Questo articolo si propone di essere un primer sulle animazioni iOS con l’intento di coprire in modo esaustivo i diversi modi di fare lo stesso.
Data l’ampiezza dell’argomento, copriremmo ogni parte in modo succinto ad un livello abbastanza alto. L’obiettivo è educare il lettore con una serie di scelte per aggiungere animazioni alla sua app iOS.
Prima di iniziare con argomenti relativi a iOS, diamo una breve occhiata alla velocità di animazione.
Animazione A 60FPS
Generalmente nei video, ogni fotogramma è rappresentato da un’immagine e la frequenza dei fotogrammi determina il numero di immagini capovolte nella sequenza. Questo è definito come ‘fotogrammi al secondo’ o FPS.
FPS determina il numero di immagini fisse capovolte in un secondo, il che significa letteralmente che più il numero di immagini/ fotogrammi, più dettagli/ informazioni vengono visualizzate nel video. Questo vale anche per le animazioni.
FPS viene in genere utilizzato per determinare la qualità delle animazioni. C’è un’opinione popolare che qualsiasi buona animazione dovrebbe funzionare a 60fps o superiore — qualcosa di meno di 60fps si sentirebbe un po ‘ fuori.
Vuoi vedere la differenza tra 30FPS e 60FPS? Guarda qui!
Hai notato la differenza? Gli occhi umani possono sicuramente sentire il jitter a fps più bassi. Quindi, è sempre una buona pratica per assicurarsi che qualsiasi animazione si crea, aderisce alla regola di base di esecuzione a 60FPS o superiore. Questo lo fa sentire più realistico e vivo.
Dopo aver esaminato FPS, approfondiamo ora i diversi framework iOS di base che ci forniscono un modo per eseguire animazioni.
Core Frameworks
In questa sezione, toccheremo i framework nell’SDK di iOS che possono essere utilizzati per creare animazioni di visualizzazione. Faremo una breve passeggiata attraverso ciascuno di essi, spiegando il loro set di funzionalità con un esempio pertinente.
Animazioni UIKit/UIView
UIView è la classe base per qualsiasi vista che visualizza contenuti nelle app iOS.
UIKit, il framework che ci dà UIView, ci fornisce già alcune funzioni di animazione di base che rendono conveniente per gli sviluppatori ottenere di più facendo meno.
L’API, UIView.animate
, è il modo più semplice per animare le viste poiché le proprietà di qualsiasi vista possono essere facilmente animate fornendo i valori delle proprietà nella sintassi basata su blocchi.
Nelle animazioni UIKit, si consiglia di modificare solo le proprietà animabili di UIVIew altrimenti ci saranno ripercussioni in cui le animazioni potrebbero causare la fine della vista in uno stato imprevisto.
animation (withDuration: animations: completion)
Questo metodo accetta la durata dell’animazione, un insieme di modifiche alle proprietà animabili della vista che devono essere animate. Il blocco di completamento fornisce un callback quando la vista è terminata con l’esecuzione dell’animazione.
Quasi qualsiasi tipo di animazione come lo spostamento, il ridimensionamento, la rotazione, lo sbiadimento, ecc. su una vista può essere raggiunto con questa singola API.
Ora, si consideri che si desidera animare un cambiamento di dimensione del pulsante o si desidera una vista particolare per ingrandire lo schermo. Ecco come possiamo farlo usando l’APIUIView.animate
:
let newButtonWidth: CGFloat = 60UIView.animate(withDuration: 2.0) { //1 self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) //2 self.button.center = self.view.center //3}
Ecco cosa stiamo facendo qui:
- Chiamiamo il metodo
UIView.animate
con un valore di duration passato ad esso che rappresenta la durata dell’animazione, descritta all’interno del blocco, dovrebbe essere eseguita. - Impostiamo la nuova cornice del pulsante che dovrebbe rappresentare lo stato finale dell’animazione.
- Impostiamo il pulsante
center
con il centro della superview in modo che rimanga al centro dello schermo.
Il precedente blocco di animazione codice dovrebbe attivare l’animazione del pulsante di cambio telaio dal fotogramma corrente:
Width = 0, Height = 0
Per il fotogramma finale:
Width = Height = newButtonWidth
Ed ecco che l’animazione sarebbe simile:
animateWithDuration
Questo metodo è come un’estensione del metodo animate in cui puoi fare tutto ciò che puoi eseguire nell’API precedente con alcuni comportamenti fisici aggiunti alle animazioni della vista.
Ad esempio, se si desidera ottenere effetti di smorzamento della molla nell’animazione che abbiamo fatto sopra, allora questo è il modo in cui il codice sarebbe simile:
let newButtonWidth: CGFloat = 60UIView.animate(withDuration: 1.0, //1 delay: 0.0, //2 usingSpringWithDamping: 0.3, //3 initialSpringVelocity: 1, //4 options: UIView.AnimationOptions.curveEaseInOut, //5 animations: ({ //6 self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) self.button.center = self.view.center}), completion: nil)
Ecco il set di parametri che usiamo:
-
duration
Rappresenta la durata dell’animazione che determina la durata del blocco di codice. -
delay
Rappresenta il ritardo iniziale che vogliamo avere prima dell’inizio dell’animazione. -
SpringWithDamping
Rappresenta il valore dell’effetto elastico che vogliamo che la vista si comporti. Il valore deve essere compreso tra 0 e 1. Più basso è il valore, maggiore è l’oscillazione della molla. -
velocity
Rappresenta la velocità con cui l’animazione dovrebbe iniziare. -
options
Tipo di curva di animazione che si desidera applicare all’animazione della vista. - Infine, il blocco di codice in cui impostiamo la cornice del pulsante che deve essere animato. È lo stesso dell’animazione precedente.
Ed ecco come sarebbe l’animazione con la configurazione di animazione sopra:
UIViewPropertyAnimator
Per un po ‘ più di controllo sulle animazioni, UIViewPropertyAnimator
è utile dove ci fornisce un modo per mettere in pausa e riprendere le animazioni. Puoi avere tempi personalizzati e avere la tua animazione interattiva e interrompibile. Questo è molto utile quando si eseguono animazioni che sono anche interagibili con le azioni dell’utente.
Il classico gesto ‘Slide to Unlock’ e la vista del giocatore respingere / espandere l’animazione (nell’app Musica) sono esempi di animazioni interattive e interrompibili. Puoi iniziare a spostare una vista con il dito, quindi rilasciarla e la vista tornerà alla sua posizione originale. In alternativa, puoi catturare la vista durante l’animazione e continuare a trascinarla con il dito.
Di seguito è riportato un semplice esempio di come potremmo ottenere l’animazione usando UIViewPropertyAnimator
:
let newButtonWidth: CGFloat = 60let animator = UIViewPropertyAnimator(duration:0.3, curve: .linear) { //1 self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) self.button.center = self.view.center}animator.startAnimation() //2
Ecco cosa stiamo facendo:
- Chiamiamo l’API
UIViewProperty
passando la durata e la curva di animazione. - A differenza di entrambi i precedenti UIView.animate API, l’animazione non si avvia a meno che non lo specifichi da solo, ovvero hai il pieno controllo del processo/ flusso di animazione completo.
Ora, diciamo che vuoi ancora più controllo sulle animazioni. Ad esempio, si desidera progettare e controllare ogni fotogramma nell’animazione. C’è un’altra API per questo, animateKeyframes
. Ma prima di approfondire, diamo un’occhiata rapidamente a cos’è una cornice, in un’animazione.
Che cos’è unframe
?
Una raccolta delle modifiche/ transizioni del fotogramma della vista, dallo stato iniziale allo stato finale, è definita comeanimation
e ogni posizione della vista durante l’animazione è chiamata comeframe
.
animateKeyframes
Questa API fornisce un modo per progettare l’animazione in modo tale da poter definire più animazioni con tempi e transizioni diversi. Pubblica questo, l’API integra semplicemente tutte le animazioni in un’unica esperienza senza interruzioni.
Diciamo che vogliamo spostare il nostro pulsante sullo schermo in modo casuale. Vediamo come possiamo usare l’API di animazione keyframe per farlo.
UIView.animateKeyframes(withDuration: 5, //1 delay: 0, //2 options: .calculationModeLinear, //3 animations: { //4 UIView.addKeyframe( //5 withRelativeStartTime: 0.25, //6 relativeDuration: 0.25) { //7 self.button.center = CGPoint(x: self.view.bounds.midX, y: self.view.bounds.maxY) //8 } UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.25) { self.button.center = CGPoint(x: self.view.bounds.width, y: start.y) } UIView.addKeyframe(withRelativeStartTime: 0.75, relativeDuration: 0.25) { self.button.center = start }})
Ecco la ripartizione:
-
duration
Chiamare l’API passando la durata dell’animazione. -
delay
Durata del ritardo iniziale dell’animazione. -
options
Il tipo di curva di animazione che si desidera applicare all’animazione della vista. -
animations
Blocco che accetta tutte le animazioni dei fotogrammi chiave progettate dallo sviluppatore/ utente. -
addKeyFrame
Chiama l’API per progettare ogni animazione. Nel nostro caso, abbiamo definito ogni mossa del pulsante. Possiamo avere tante animazioni di cui abbiamo bisogno, aggiunte al blocco. -
relativeStartTime
Definisce l’ora di inizio dell’animazione nella raccolta del blocco di animazione. -
relativeDuration
Definisce la durata complessiva di questa specifica animazione. -
center
Nel nostro caso, cambiamo semplicemente la proprietà center del pulsante per spostare il pulsante sullo schermo.
Ed ecco come appaiono le animazioni finali:
CoreAnimation
Qualsiasi animazione basata su UIKit viene tradotta internamente in animazioni core. Pertanto, il framework Core Animation funge da livello di supporto o backbone per qualsiasi animazione UIKit. Quindi, tutte le API di animazione UIKit non sono altro che strati incapsulati delle API di animazione di base in modo facilmente consumabile o conveniente.
Le API di animazione UIKit non forniscono molto controllo sulle animazioni che sono state eseguite su una vista poiché vengono utilizzate principalmente per le proprietà animabili della vista. Quindi in questi casi, in cui si intende avere il controllo su ogni fotogramma dell’animazione, è preferibile utilizzare direttamente le API di animazione di base sottostanti. In alternativa, sia le animazioni UIView che le animazioni di base possono essere utilizzate anche in combinazione.
UIView + Core Animation
Vediamo come possiamo ricreare lo stesso pulsante cambia animazione insieme a specificare la curva di temporizzazione utilizzando le API UIView e Core Animation.
Possiamo usare CATransaction
‘s funzioni di temporizzazione, che consente di specificare e controllare la curva di animazione.
Diamo un’occhiata a un esempio di animazione di modifica delle dimensioni del pulsante con il suo raggio d’angolo utilizzando la funzione di temporizzazione diCATransaction
e una combinazione di animazioni UIView:
let oldValue = button.frame.width/2let newButtonWidth: CGFloat = 60/* Do Animations */CATransaction.begin() //1CATransaction.setAnimationDuration(2.0) //2CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)) //3// View animations //4UIView.animate(withDuration: 1.0) { self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) self.button.center = self.view.center}// Layer animationslet cornerAnimation = CABasicAnimation(keyPath: #keyPath(CALayer.cornerRadius)) //5cornerAnimation.fromValue = oldValue //6cornerAnimation.toValue = newButtonWidth/2 //7button.layer.cornerRadius = newButtonWidth/2 //8button.layer.add(cornerAnimation, forKey: #keyPath(CALayer.cornerRadius)) //9CATransaction.commit() //10
Ecco la ripartizione:
-
begin
Rappresenta l’inizio del blocco di codice di animazione. -
duration
Durata complessiva dell’animazione. -
curve
Rappresenta la curva di temporizzazione che deve essere applicata all’animazione. -
UIView.animate
La nostra prima animazione per cambiare la cornice del pulsante. -
CABasicAnimation
Creiamo l’oggettoCABasicAnimation
facendo riferimento alcornerRadius
del pulsante come keypath poiché è ciò che vogliamo animare. Allo stesso modo, se si desidera avere un controllo di livello granulare sulle animazioni dei fotogrammi chiave, è possibile utilizzare la classeCAKeyframeAnimation
. -
fromValue
Rappresenta il valore iniziale dell’animazione, cioè il valore inizialecornerRadius
del pulsante da cui l’animazione deve iniziare. -
toValue
Rappresenta il valore finale dell’animazione, cioè il valore finalecornerRadius
del pulsante in cui l’animazione deve terminare. -
cornerRadius
Dobbiamo impostare la proprietàcornerRadius
del pulsante con il valore finale dell’animazione altrimenti il valore cornerRadius del pulsante verrà automaticamente ripristinato al suo valore iniziale dopo il completamento dell’animazione. -
addAnimation
Colleghiamo l’oggetto animazione che contiene la configurazione dell’intero processo di animazione al livello rappresentando il Keypath per il quale l’animazione deve essere eseguita. -
commit
Rappresenta la fine del blocco di codice dell’animazione e inizia l’animazione.
Questa è come l’animazione finale sarà simile:
Questo blog è una grande lettura per aiutare a creare più avanzate animazioni, come ben illustra la maggior parte del Core Animation framework Api con istruzioni per guidare l’utente attraverso ogni passo del cammino.
UIKitDynamics
Uikit Dynamics è il motore fisico per UIKit che consente di aggiungere qualsiasi comportamento fisico come collisione, gravità, spinta, scatto, ecc.
UIKitDynamicAnimator
Questa è la classe admin del framework UIKIT Dynamics che regola tutte le animazioni attivate da un dato controllo dell’interfaccia utente.
UIKitDynamicBehavior
Consente di aggiungere qualsiasi comportamento fisico a un animatore che quindi consente di eseguire sulla vista ad esso collegata.
Diversi tipi di comportamenti per UIKitDynamics includono:
UIAttachmentBehavior
UICollisionBehavior
UIFieldBehavior
UIGravityBehavior
UIPushBehavior
UISnapBehavior
L’architettura di UIKitDynamics sembra qualcosa di simile a questo. Si noti che gli elementi da 1 a 5 possono essere sostituiti con una singola vista.
Applichiamo alcuni comportamenti fisici al nostro pulsante. Vedremo come applicare la gravità al pulsante in modo che ci dia la sensazione di avere a che fare con un oggetto reale.
var dynamicAnimator : UIDynamicAnimator!var gravityBehavior : UIGravityBehavior!dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1gravityBehavior = UIGravityBehavior(items: ) //2dynamicAnimator.addBehavior(gravityBehavior) //3
Ecco la ripartizione:
-
UIKitDynamicAnimator
Abbiamo creato un oggettoUIKitDynamicAnimator
che funge da orchestratore per l’esecuzione di animazioni. Abbiamo anche passato la superview del nostro pulsante come vista di riferimento. -
UIGravityBehavior
Abbiamo creato un oggettoUIGravityBehavior
e passiamo il nostro pulsante negli elementi dell’array su cui viene iniettato questo comportamento. -
addBehavior
Abbiamo aggiunto l’oggetto gravità all’animatore.
Questo dovrebbe creare un’animazione come mostrato di seguito:
Dovremmo dire all’animatore di considerare la parte inferiore dello schermo come il terreno. Questo è dove
UICollisionBehavior
entra in foto.var dynamicAnimator : UIDynamicAnimator!var gravityBehavior : UIGravityBehavior!var collisionBehavior : UICollisionBehavior!dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1gravityBehavior = UIGravityBehavior(items: ) //2dynamicAnimator.addBehavior(gravityBehavior) //3collisionBehavior = UICollisionBehavior(items: ) //4collisionBehavior.translatesReferenceBoundsIntoBoundary = true //5dynamicAnimator.addBehavior(collisionBehavior) //6
-
UICollisionBehavior
Abbiamo creato un oggettoUICollisionBehavior
e passato lungo il pulsante in modo che il comportamento venga aggiunto all’elemento. -
translatesReferenceBoundsIntoBoundary
L’abilitazione di questa proprietà indica all’animatore di prendere il limite delle viste di riferimento come fine, che è la parte inferiore dello schermo nel nostro caso. -
addBehavior
Abbiamo aggiunto il comportamento di collisione all’animatore qui.
Ora, il nostro pulsante dovrebbe colpire il terreno e stare fermo come mostrato di seguito:
È abbastanza pulito, non è vero?
Ora, proviamo ad aggiungere un effetto di rimbalzo in modo che il nostro oggetto si senta più reale. Per fare ciò, useremo la classeUIDynamicItemBehavior
.var dynamicAnimator : UIDynamicAnimator!var gravityBehavior : UIGravityBehavior!var collisionBehavior : UICollisionBehavior!var bouncingBehavior : UIDynamicItemBehavior!dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1gravityBehavior = UIGravityBehavior(items: ) //2dynamicAnimator.addBehavior(gravityBehavior) //3collisionBehavior = UICollisionBehavior(items: ) //4collisionBehavior.translatesReferenceBoundsIntoBoundary = true //5dynamicAnimator.addBehavior(collisionBehavior) //6//Adding the bounce effectbouncingBehavior = UIDynamicItemBehavior(items: ) //7bouncingBehavior.elasticity = 0.75 //8dynamicAnimator.addBehavior(bouncingBehavior) //9
-
UIDynamicItemBehavior
Abbiamo creato un oggettoUIDynamicItemBehavior
e passiamo lungo il pulsante in modo che il comportamento venga aggiunto all’elemento. -
elasticity
Il valore deve essere compreso tra 0-1, rappresenta l’elasticità cioè il numero di volte in cui l’oggetto deve rimbalzare su e giù dal terreno quando viene colpito. È qui che avviene la magia: modificando questa proprietà, puoi distinguere tra diversi tipi di oggetti come palle, bottiglie, oggetti duri e così via. -
addBehavior
Abbiamo aggiunto il comportamento di collisione all’animatore qui.
Ora, il nostro pulsante dovrebbe rimbalzare quando colpisce il suolo, come indicato di seguito:
Questo repository è molto utile e mostra tutti UIKitDynamics comportamenti in azione. Fornisce anche il codice sorgente per giocare con ogni comportamento. Questo, a mio parere, dovrebbe servire come un ampio elenco di modi per eseguire animazioni iOS sulle visualizzazioni!
Nella prossima sezione, daremo una breve occhiata agli strumenti che ci aiuteranno a misurare le prestazioni delle animazioni. Ti consiglierei anche di esaminare i modi per ottimizzare la tua build Xcode poiché farà risparmiare un’enorme quantità di tempo di sviluppo.
Ottimizzazione delle prestazioni
In questa sezione, esamineremo i modi per misurare e ottimizzare le prestazioni delle animazioni iOS. Come sviluppatore iOS, potresti aver già utilizzato strumenti Xcode come perdite di memoria e allocazioni per misurare le prestazioni dell’app complessiva. Allo stesso modo, ci sono strumenti che possono essere utilizzati per misurare le prestazioni delle animazioni.
Core Animation
Strumento
Prova lo strumento Core Animation
e dovresti essere in grado di vedere gli FPS forniti dalla schermata dell’app. Questo è un ottimo modo per misurare le prestazioni/ velocità di qualsiasi animazione renderizzata nella tua app iOS.
Disegno
FPS è notevolmente abbassato in app che visualizza contenuti pesanti come le immagini con effetti come le ombre. In questi casi, invece di assegnare l’immagine direttamente alla proprietà immagine UIImageView
, provare a disegnare l’immagine separatamente in un contesto utilizzando le API grafiche di base. Ciò riduce eccessivamente il tempo di visualizzazione dell’immagine eseguendo la logica di decompressione dell’immagine in modo asincrono quando eseguita in un thread separato anziché nel thread principale.
Rasterizzazione
La rasterizzazione è un processo utilizzato per memorizzare nella cache informazioni di livello complesse in modo che queste viste non vengano ridisegnate ogni volta che vengono renderizzate. Il ridisegno delle viste è la causa principale della riduzione degli FPS e, quindi, è meglio applicare la rasterizzazione sulle viste che verranno riutilizzate più volte.
Avvolgendo
Per concludere, ho anche riassunto un elenco di risorse utili per le animazioni iOS. Si può trovare questo molto utile quando si lavora su animazioni iOS. Inoltre, puoi anche trovare questo set di strumenti di progettazione utile come passo (progettazione) prima di approfondire le animazioni.