Articles

Esecuzione di iOS Animazioni Viste Con UIKit E UIView

  • 14 min leggere
  • Animazione,iOS,UI,Mobile
  • Salvate per la lettura offline
  • Condividi su Twitter”, LinkedIn
Questo articolo vuole essere un primer su iOS animazioni che copre in modo esaustivo i diversi modi di fare così. Iniziamo capendo le basi delle animazioni, passiamo ai framework di base costruendo un singolo esempio utilizzando i diversi metodi offerti e infine esaminando i modi per ottimizzare le prestazioni.

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:

  1. 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.
  2. Impostiamo la nuova cornice del pulsante che dovrebbe rappresentare lo stato finale dell’animazione.
  3. 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:

  1. duration
    Rappresenta la durata dell’animazione che determina la durata del blocco di codice.
  2. delay
    Rappresenta il ritardo iniziale che vogliamo avere prima dell’inizio dell’animazione.
  3. 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.
  4. velocity
    Rappresenta la velocità con cui l’animazione dovrebbe iniziare.
  5. options
    Tipo di curva di animazione che si desidera applicare all’animazione della vista.
  6. 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:

  1. Chiamiamo l’APIUIViewProperty passando la durata e la curva di animazione.
  2. 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 comeanimatione 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:

  1. duration
    Chiamare l’API passando la durata dell’animazione.
  2. delay
    Durata del ritardo iniziale dell’animazione.
  3. options
    Il tipo di curva di animazione che si desidera applicare all’animazione della vista.
  4. animations
    Blocco che accetta tutte le animazioni dei fotogrammi chiave progettate dallo sviluppatore/ utente.
  5. 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.
  6. relativeStartTime
    Definisce l’ora di inizio dell’animazione nella raccolta del blocco di animazione.
  7. relativeDuration
    Definisce la durata complessiva di questa specifica animazione.
  8. 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 diCATransactione 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:

  1. begin
    Rappresenta l’inizio del blocco di codice di animazione.
  2. duration
    Durata complessiva dell’animazione.
  3. curve
    Rappresenta la curva di temporizzazione che deve essere applicata all’animazione.
  4. UIView.animate
    La nostra prima animazione per cambiare la cornice del pulsante.
  5. 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 classe CAKeyframeAnimation.
  6. fromValue
    Rappresenta il valore iniziale dell’animazione, cioè il valore inizialecornerRadius del pulsante da cui l’animazione deve iniziare.
  7. toValue
    Rappresenta il valore finale dell’animazione, cioè il valore finalecornerRadius del pulsante in cui l’animazione deve terminare.
  8. 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.
  9. 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.
  10. 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:

  1. 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.
  2. UIGravityBehavior
    Abbiamo creato un oggetto UIGravityBehavior e passiamo il nostro pulsante negli elementi dell’array su cui viene iniettato questo comportamento.
  3. addBehavior
    Abbiamo aggiunto l’oggetto gravità all’animatore.
    Questo dovrebbe creare un’animazione come mostrato di seguito:
    Si noti come il pulsante cade dal centro (la sua posizione originale) dello schermo verso il basso e oltre.

    Dovremmo dire all’animatore di considerare la parte inferiore dello schermo come il terreno. Questo è doveUICollisionBehavior 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
  4. UICollisionBehavior
    Abbiamo creato un oggettoUICollisionBehavior e passato lungo il pulsante in modo che il comportamento venga aggiunto all’elemento.
  5. 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.
  6. 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
  7. UIDynamicItemBehavior
    Abbiamo creato un oggetto UIDynamicItemBehavior e passiamo lungo il pulsante in modo che il comportamento venga aggiunto all’elemento.
  8. 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.
  9. 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.