Compatibile con Xcode 8

Tutorial UIKit in Swift. Come animare la propria applicazione

ENTRA NEL NOSTRO GRUPPO FACEBOOK

Sembrerà una cosa campata in aria, ma quando un’app ha una grafica dinamica, essa genera più attrazione rispetto ad Tutorial UIKit in Swift, creare un menu base
un’applicazione con grafica statica.

Per interfaccia dinamica si intende un layout che risponde agli eventi come tocchi, trascinamento e cambio d’orientamento. Non è un caso che, da quando Apple ha abbandonato lo scheumorfismo, ovvero il tentativo di creare un layout che si avvicinasse alla realtà (vedi ibooks o note), ha avuto un incremento positivo dell’user experience che gli ha permesso di riottenere il primato, tra le altre società, per i dispositivi più venduti negli ultimi anni.

Adesso la nuova parola d’ordine di ogni programmatore e sviluppatore non è tanto il look real ma quanto il feel real. Dare la sezione che l’app risponda e dia dei segnali a degli eventi, che l’utente genera, è sinonimo di stretta relazione tra app e utente. L’utente, che sia un programmatore o un utilizzatore, cerca sempre di entrare in simbiosi con l’app che sta utilizzando ed uno dei modi per permettere questa connessione è proprio la presenza di un layout dinamico.

Ma come posso movimentare un layout?

Il framework UIKit è la risposta a tutte le tue domande.

Con il framework UIKit o User Interface Kit sarai in grado di aggiungere e gestire il movimento delle tue View. Qual’è il meccanismo che sta alla base?

Grazie alla simulazione delle leggi fisiche, fardello di tutti gli studenti, sarai in grado di applicare delle forze agli oggetti che compongono la tua interfaccia. Le forze applicate faranno in modo che il tuo oggetto si muova in una direzione o nell’altra. Un po’ come se la View principale della tua applicazione si comportasse da mondo fisico a tutti gli effetti. Ad esempio, una delle sue caratteristiche sarà quella della presenza della gravità che porterà gli oggetti a scendere verso il basso!

In sostanza, con questo tutorial UIKit in Swift, tratterò tutti i metodi principali per movimentare un oggetto grafico della tua applicazione con il linguaggio Swift

Il tutorial è aggiornato e testato per funzionare con il linguaggio Swift 2.0 ed Xcode 7 o versioni successive.

5 cose che imparerai da questo tutorial

Ecco ciò che verrà trattato in questo tutorial UIKit in Swift:

  1. Gestione della gravità e delle collisioni tra oggetti.
  2. Lo Snap di un oggetto o movimento di un oggetto verso un punto toccato da utente.
  3. Push su un oggetto, come applicare una forza ad una View.
  4. L’Attach tra due oggetti. Far seguire il movimento di un oggetto spostandone un altro.
  5. Un esempio di UIKit Dynamics applicato ad un progetto reale.

Una volta viste tutte le configurazioni base che si possono creare, utilizzando le dinamiche proposte dal framework UIKit, ti farò vedere come utilizzarle per creare un progetto reale, creerai un menu laterale con il linguaggio Swift, che potrai utilizzare per abbellire le tue applicazioni.

Let’s start! la creazione di un progetto base

Non c’è molto da configurare ed i passaggi per creare un progetto dovrebbero già esserti noti, quindi concedimi di andare un po’ più veloce in questi punti.

Apri Xcode, vai su File\New\Project…, seleziona iOS, Single View Application e premi Next. Aggiungi il nome al progetto, assicurati di aver selezionato il linguaggio Swift e clicca su Next. Sceglia la destinazione del progetto e infine clicca su Create.

Passa al ViewController.swift

Sotto la definizione della classe ViewController, aggiungi un attributo, di tipo UIView, che utilizzerai per la gestione della View a cui applicherai le forze:

Istanzia, nel ViewDidLoad, una UIView di forma quadrata e assegnala all’attributo squareView:

Una UIView è un oggetto grafico creato a partire da delle dimensioni, nel nostro caso di forma rettangolare CGRect, che verrà visualizzato alla coordinata x: 100, y:100 e avrà dimensioni, altezza e larghezza, uguali a 100 pixel.

Alla view, squareView, viene cambiato il colore di background backgroundColor assegnandogli il colore rosso UIColor.red.

Infine la squareView viene attaccata alla view principale del ViewController con il metodo addSubview, permettendo così la visualizzazione del quadrato.

Avvia l’app, dovresti vedere il quadrato appena creato:

UIView e CGRect

Esempio di UIView inserita da codice.

Rendere l’UIView compatibile con tutte le dimensioni dei dispositivi

Ovviamente, cambiando dispositivo, il quadrato verrà renderizzato in punti apparentemente differenti dato il cambio di dimensioni del layout. Per poter risolvere questo problema puoi prendere le dimensioni della view principale, calcolare il centro e su quello gestire la posizione relativa del quadrato.

L’origine del quadrato, per quanto riguarda la coordinate x, viene calcolata a partire dal centro della view principale (view.center.x) a cui poi vengono sottratti 50, che corrispondono alla metà del lato del quadrato (In questo modo il centro del quadrato è centrato con il centro della view).

Per centrare l’origine verticale, la coordinate y, viene settata alla massima altezza che ha la View. Così facendo, anche cambiando dispositivo, verrà sempre piazzato in alto.

Infine, il ViewDidLoad dovrebbe avere questo codice all’interno:

che genera questo risultato:

UIView e CGRect ottimizzato per tutti i layout

Sentiti libero di utilizzare l’implementazione che preferisci!

gravità

Aggiungere la Gravità ad una View con UIGravityBehavior

Eh si, le leggi di Newton hanno influenzato anche la programmazione. Quanto danno può fare una mela che cade su una testa!

Aggiungi, sotto il parametro squareView, questi due parametri:

L’UIDynamicAnimator è l’oggetto delegato alla gestione delle forze fisiche, l’engine della fisica dell’applicazione. L’animator è un’entità astratta e per poterla rendere reale va applicata ad un oggetto che si trasformerà nel mondo fisico di riferimento. L’UIDynamicAnimator viene spesso associato alla view principale in modo da contenere al suo interno tutti gli oggetti della View e quindi potergli applicare le forze.

L’UIGravityBehavior è il gestore della forza di gravità. A questo oggetto verranno associati tutti gli altri oggetti che verranno influenzati dalla forza di gravità, infine il behavior verrà gestito dall’Animator che penserà a diffondere la forza all’interno del suo spazio.

Quindi l’UIDynamicAnimator puoi considerarlo come la terra, nella terra infatti oltre alla gravità esistono altre forze, ed i Behavior le varie forze che si trovano all’interno della terra.

Adesso nel ViewDidLoad aggiungi questo codice:

La referenceView è la view che gestirà l’animator. Così, l’animator è associato alla view (la view o self.view è la view principale del ViewController).

Ora, per la gestione della gravità, crea una funzione ad hoc chiamata add_gravity:

La funzione accetta in ingresso un array di UIView, ovvero gli oggetti a cui verrà applicata la gravità. Una volta che la behavior gravità viene applicata agli items, l’oggetto UIGravityBehavior viene aggiunto all’animator.

Torna al viewDidLoad e aggiungi la chiamata alla funzione add_gravity:

Avvia l’applicazione eeee tadaaan! anche la gravità ha preso il sopravvento sulla tua applicazione:

UIGravityBehavior in Swift e UIDynamicAnimator

fisica

Un po’ di fisica applicata all’informatica, la relazione tra accelerazione e tempo

Con che velocità cade la UIView?

Se la gravità viene applicata sulla UIView è facile pensare come essa cada con un’accelerazione di 9,8 metri al secondo quadrato (m/s^2).

Ovviamente le unità di misura di una UIView non sono espresse in metri bensì in pixel quindi è un po’ complicato determinare la velocità con i nostri metodi standard. Infatti 9,8 m/s^2 in informatica equivalgono a 1000 punti al secondo quadrato.

Quindi se applichi la relazione che collega lo spazio con l’accelerazione, puoi determinare il tempo che impiega una View, che parte dal punto Y=0, a percorrere uno spazio S.

Se consideri la S da percorrere come le dimensioni dello schermo dell’iphone 6, che corrispondono a 667 punti pixel, la S iniziale, la cima dello schermo (coordinate y=0) e la velocità iniziale 0, puoi facilmente individuare il tempo che impiega lo squareView a percorrere tutto lo schermo:

Infine, lo squareView impiega 1,15 secondi a percorrere tutta la view.

Peppeee, io volevo scrivere codice, non risolvere problemi di fisica!

Hai perfettamente ragione! però alcune volte risulta importante conoscere come gli oggetti interagiscono con il mondo e certe volte queste formule ti torneranno utili quando avrai la necessità di modificare il comportamento degli oggetti.

Infatti solo cambiando l’accelerazione di gravità sarai in grado di mostrare una UIView ad un istante X rispetto ad un altro.

tu non puoi passare!!!La gestione delle collisioni con UICollisionBehavior. Rendere una view un muro insuperabile

Sicuramente avrai notato come il quadrato scompare sotto la parte inferiore della view. Per poter risolvere questo problema e quindi bloccare la view ad una determinata altezza, è necessario inserire un muro invisibile che arresti la caduta.

Aggiungi un nuovo behavior chiamato collision:

Allo stesso modo di quanto fatto per la gravità, aggiungi una funzione per la collisione:

Il funzionamento è pressoché lo stesso, in più con il translatesReferenceBoundsIntoBoundary fa in modo che vengano impostati dei confini generali presi dalla refence dell’animator. La reference, ti ricordo, è la view principale del ViewController. Quindi i confini della view faranno da blocco a qualsiasi oggetto che proverà ad attreversarli.

Nel viewDidLoad, chiama la funzione:

Una volta che avvii l’app, la view cadrà, toccherà il bordo inferiore, rimbalzerà e concluderà il suo movimento fermandosi sopra il confine:

UICollisionBehavior in Swift e UIDynamicAnimator

Fermare una UIView ad una certa posizione ben definita con addBoundaryWithIdentifier

Nel caso in cui non volessi far scendere la view fino al bordo inferiore del suo container, puoi delimitare un confine in una posizione da te definita.

Fare una cosa del genere, in gergo, viene definita come: l’aggiunta di una boundary. Se sei un lettore del blog o comunque hai già un po’ di dimestichezza in altri settori, sai che questo termine viene utilizzato per i giochi per delimitare il confine fisico di una sprite.

Nella funzione add_collision, aggiungi la seguente riga di codice:

In questo modo viene aggiunta una boundary addBoundary, chiamata “barriera” che, parte dal punto x:0 e y: metà dell’altezza del dispositivo e finisce al punto diametralmente opposto, ovvero x: larghezza dispositivo e y: metà dell’altezza.

Se adesso avvii l’applicazione, la view quadrato, attratta dalla gravità, si fermerà esattamente a metà della view principale:

UIView, gravità e boundary in swift

Snap di una view con UISnapBehavior

Snap, scattare verso un punto, è la capacità di un oggetto di traslare, da una posizione A ad una posizione B, passando per tutte le posizioni intermedie.

Per poter sfruttare questo behavior hai bisogno di conoscere le coordinate del punto B in cui traslare la view (A lo conosci dato che sono le coordinate dello squareView) e pertanto considereremo il punto B come il punto in cui l’utente tocca lo schermo.

Per poter catturare il punto in cui l’utente tocca lo schermo, devi utilizzare un oggetto chiamato UITapGestureRecognizer (ricognitore di tap gesture).

Aggiungi il behavior UISnapBehavior sotto quelli già presenti:

Spostati nel Main.storyboard e, dall’object library, trascina un oggetto Tap Gesture Recognizer all’interno del ViewController:

Tap Gesture Recognizer in Swift

Poi crea una IBAction per il Tap Gesture Recognizer, chiamala tap_recognizer e imposta come type: UITapGestureRecognizer. All’interno inserisci il seguente codice:

prima viene recuperata la coordinata del punto toccato sullo schermo con la locationInView, poi viene chiamata la funzione add_snap (ho dimenticato di fartela aggiungere prima) che vuole passato come parametro, l’oggetto da muovere object il punto in cui muoverlo toPoint. La funzione si comporta così:

  • Se lo snap è diverso da nil, ovvero c’è già uno span in azione, lo rimuove dall’animator
  • Fatto il controllo, aggiunge il behavior all’item squareView comunicandogli la posizione in cui traslare (snapToPoint) e aggiunge il behavior all’animator.

In questo modo, con l’if, si evitano che più snap si sovrappongano tra loro. Fai delle prove togliendo l’if.

Prima di avviare l’app, ricordati di commentare, dal viewDidLoad, le funzioni add_gravity e add_collision:

UISnapBehavior in Swift

Aggiungere una relazione tra due view o tra una view ed un punto con UIAttachBehavior

Il behavior UIAttachmentBehavior può essere utilizzato per rendere una view dipendente da un’altra. Il principio è simile a quello dei vincoli di auto layout, si definisce o si crea una figura e si crea un vincolo tra questa figura e la figura da ancorargli, così facendo la figura ancorata dipenderà da ciò che accade alla figura genitore.

Per prima cosa, modifica la posizione dello squareView, posizionandolo al centro:

Crea una nuova view, chiamala anchorView, leggermente più piccola della precedente e posizionala sopra rispetto allo squareView:

Aggiungi il UIAttachmentBehavior:

Ed infine, aggiungi la seguente funzione add_attachment:

Nel viewDidLoad, fai la chiamata alla funzione e tieni commentata solo l’add_collision:

Avvia l’applicazione:

UIAttachmentBehavior in Swift

Come puoi ben notare, pur provando a fare lo snap in un punto qualsiasi, la squareView si trova costretta a ruotare solo interno all’anchorView.

forze istantanee e costanti

Applicare una forza costante nel tempo o istantanea ad una view con UIPushBehavior

Per il momento, oltre alla forza di gravità e allo snap, non c’è nessun altro modo per poter muovere un oggetto o per poterlo muovere con una velocità rispetto ad un’altra.

Come accade nella realtà, è possibile applicare una forza ad una view e quest’ultima, se non è ancorata, verrà mossa nel verso della forza.

Ancora un po’ di fisica! Un accenno alla fisica di una forza

Ti ricordo che forze sono vettori, quindi oltre che da un’intensità sono caratterizzate da un verso di applicazione. Ora! non voglio perdermi in discorsi fisici, ma solo perché mi sembra giusto parlarne, l’equazione della forza è definita dalla seguente espressione:

Dove:

  • F” è la forza
  • m” è la massa
  • v” è la velocità

Questo vuol dire che, data una massa “m”, che si muove ad una certa velocità “v”, la forza risultante è direttamente proporzionale al prodotto tra “v” e “m”.

Questo però non basta, infatti dato che le forze sono vettori è necessario definire un verso d’applicazione.

Ora pensa ad una frombola (la fionda a rotazione, quella di Davide vs Golia), se la metti in moto vedrai che, pur descrivendo con la sua corda un cerchio attorno a te (moto circolare), la pallina viene schizzata in avanti in linea retta.

Quindi pur muovendosi di moto circolare, una volta che il moto viene interrotto, la palla si muove in linea retta. Tale forza prende il nome di Forza Centripeta (non centrifuga come erroneamente viene chiamata, anche se sono pressoché la stessa cosa).

Perché ti ho raccontato questa storia?

Perché per spostare una view, viene utilizzato un sistema simile. Ovvero la forza con cui una UIVIew viene spinta è definita a partire da un angolo, espresso in radianti, e da una intensità.

L’applicazione di una forza con UIPushBehavior in Swift

Aggiungi il seguente behavior:

Esistono due tipi di forze (per il behavior): continua e istantanea:

  • Continua: la forza viene applicata ad ogni istante, quindi non decresce nel tempo.
  • Istantanea: la forza viene applicata solo all’inizio e poi decresce nel tempo.

Per questo motivo, viene comodo definire una enum che utilizzerai per riferirti a quale forza applicare alla view:

La funzione per la spinta di una view è la seguente:

In base al tipo di pushType scelto, la funzione setterà un behavior differente (UIPushBehaviorMode.Continuous o UIPushBehaviorMode.Istantaneous), la cosa importante da notare è la funzione setAngle:

Come primo parametro vuole l’angolo espresso in radianti… cos’è quel M_PI_2?

M_PI_2 è una costante di sistema che definisce il valore in radianti di un angolo di 90°, ovvero pigreco/2 (in valore numero corrisponde a 1.57079632679489661923132169164). Perché 90? perché in questo modo la forza sarà applicata perpendicolarmente all’asse Y (quello orizzontale) e pertanto la view si muoverà verso il basso in linea retta.

La magnitude è la forza, ed un valore di 1 corrisponde ad un’accelerazione di 100 punti al secondo quadrato.

Adesso dal viewDidLoad, commenta tutti i metodi di add, commenta il frameAncora e lascia solo quello relativo all’add_push:

UIPushBehavior continuo in SwiftQuindi la squareView cade sempre con la stessa velocità, mentre, una forza istantanea genera questo risultato:

UIPushBehavior istantanea in Swift

Ovvero la squareView decelera man mano che scorre il tempo.

Adesso non ti resta che far delle prove cambiando il valore dell’angolo e dell’intensità della forza!

Menu laterale con UIKit Dynamics ed il linguaggio Swift

Adesso è arrivato il momento di mettere insieme tutto quello appreso fino ad ora e applicarlo in qualcosa di utile. Quello che adesso ti illustrerò, è la creazione di un menu laterale, in stile vecchia applicazione di facebook, che con il movimento del dito verso destra, farà comparire un menu.

Il procedimento è abbastanza semplice e mi limiterò a descrivertelo per grandi linee dato che è semplicemente l’applicazione delle nozioni precedenti. Se vuoi seguire quello che sto per spiegarti, crea un nuovo progetto Single View Application.

Tutorial UIKit in Swift, creare un menu base

Il funzionamento generale del menu

Il menu che andrai a creare è composto dai seguenti elementi:

  1. Una view per la gestione del menu.
  2. Una view per creare un effetto di distacco tra la view principale ed il menu.
  3. Un oggetto per la gestione dei movimento del dito sullo schermo.

La view del menu, che da ora chiamerò menuView, è una view che ha dimensioni di larghezza uguale ad 1/3 delle dimensioni della view principale e altezza uguale a quelle della view.

Di default la menuView sarà trasparente e quindi non visibile all’utilizzatore.

Una volta che l’utilizzatore farà un movimento con il dito sullo schermo, verso destra, verrà invocata una funzione che presenterà il menu. La funzione in questione verrà chiamata showMenu.

La funzione che mostra il menu all’utente, la showMenu, genera delle forze che muovono il menu, dalla parte sinistra dello schermo, fino ad una certa distanza X che sarà uguale alle dimensioni dello stesso menu. Nel frattempo, oltre alla visualizzazione del menu, verrà visualizzato, accanto al menu, un’altra view che creerà l’effetto di distacco tra menu e view principale.

Quando l’utente genererà il movimento opposto, verrà richiamata sempre la showMenu, però con parametri diversi, che invertiranno le forze e spingeranno di nuovo il menu dietro il confine laterale sinistro dell’applicazione.

Il codice del menu

Se vuoi seguire quello che sto per spiegarti, crea un nuovo progetto Single View Application.

L’applicazione è composta da 1 ViewController all’interno del quale sono presenti 2 sotto view:

La overlayView servirà a creare un’effetto di trasparenza e tridimensionalità tra l’apertura del menu e la view principale, mentre la menuView rappresenta la view del menu che andrai a creare.

Servirà un animator per poter gestire il movimento della view, quindi aggiungi un animator:

Per evitare di aver codice mischiato con altro, crea un metodo, che utilizzerai per la creazione del menu, chiamato createMenu:

Allo stesso modo, aggiungi un metodo per la creazione dell’overlay, createOverlay:

Per acchiappare gli eventi gestuali generati dall’utente è necessario utilizzare un UISwipeGestureRecognizer, che si occuperò di generare gli eventi di trascinamento destro o sinistro:

Ad ogni SwipeGesture, Sinistra o Destra, viene invocato il metodo showMenu, che ha come parametro un booleano:

  • true, il menu deve essere visualizzato
  • false, il menu deve essere rimosso

In base a questo parametro vengono gestiti i valori di forza. Il codice dello showMenu è il seguente:

Infine, nel viewDidLoad, vengono istanziati i 3 metodi per il controllo e la creazione delle view:

Conclusione e Download del progetto

C’è una cosa da dire, che verrà ripresa nei prossimi tutorial, il troppo stroppia. Utilizzare troppa dinamica potrebbe rendere l’applicazione pesante sia da un punto di vista estetico che funzionale (troppa fisica potrebbe rallentare l’app). Il mio consiglio è quello di analizzare le app di successo e vedere come hanno utilizzato la dinamica all’interno delle loro applicazioni.

Mi rendo conto di essere andato veloce nella spiegazione della creazione del menu, non è un affronto nei tuoi confronti, semplicemente non volevo allungare il brodo riprendendo gli stessi argomenti.

In più ho intenzione di scrivere un tutorial tutto dedicato alla creazione di un menu laterale, quindi se non lo hai ancora fatto, iscrivi alla newsletter per rimanere aggiornato o seguici sui social.

Dove andare da qui

I tutorial che ti consiglio sono:

Download del progetto

Se hai avuto difficoltà nel seguire questo tutorial, sblocca il seguente modulo per poter scaricare i progetti fatti da me (sia del menu che della parte iniziale):

[sociallocker] [wpdm_package id=’3990′] [wpdm_package id=’4023′] [/sociallocker]

Buona Programmazione!

 

Changelog:

  • 13/10/2016 – Aggiunto il changelog. Modifiche al testo del tutorial e compatibilità dei codici con Xcode 8 e Swift 3.

Start typing and press Enter to search

Introduzione al CloudKit in iOS e SwiftAggiungere il Core Data ad un progetto esistente