SwiftUI mette a disposizione un insieme di elementi chiamati Components che ti permetteranno di assemblare l'interfaccia della tua app utilizzando dei blocchi preconfezionati.

Un esempio di component potrebbe essere List che permette di creare feed come la homepage di Instagram, Image per renderizzare immagini locali e remote o ScrollView per creare pagine che l'utente potrà scrollare.

In pratica, SwiftUI si occupa di gestire la User Interface (da qui UI) mentre tu dovrai preoccuparti solamente della logica e funzionamento dell'app.

Noi siamo partiti dal componente Text che ci ha permesso di visualizzare del testo su schermo:

Text("Welcome to LearnWithPeppe")

Oggi incontreremo due nuovi componenti di SwiftUI che saranno fondamentali per le tue interfacce: VStack ed HStack.

VStack e HStack sono contenitore che ti aiuteranno a disporre views in verticale o orizzontale.

A fine lezione sarai in grado di interpretare il codice della tua ContentView, scoprirai cos'è il body e come creare nuove var o variabili in Swift.

Ma bando alle ciance, apri o crea un progetto SwiftUI e poi entra nel file ContentView.

Let's start! 

var e body di una View

Ogni View quindi ogni pezzo di interfaccia ha una struttura del codice che è uguale indipendentemente dalle funzionalità che offre.

Da un primo sguardo alla ContentView possiamo notare come all'interno delle prime parentesi graffe c'è una linea che recita:

var body: some View {
  
}

Cosa significa?

Spezziamo la frase in due parti:

  1. var body

    1. La parola var è una parola del linguaggio Swift e significa variabile. Una variabile è un contenitore di informazioni. Espanderemo questo concetto nelle prossime lezioni.

    2. body è il tag del contenitore. Una sorta di label o etichetta che permette a Swift ed a noi sviluppatori di capire cosa c'è dentro quel contenitore.

  2. : some View

    1. I due punti stanno ad indicare che la variabile potrà contenere solamente un tipo di informazione ben specifico. Un po' come scrivere nell'etichetta di un barattolo "Qui puoi mettere solo farina Gluten Free" (il mio partner sarà super contento di questo riferimento 😂).

    2. some View puoi leggerlo come "dentro la variabile posso mettere qualsiasi tipo di View".

Infine, ciò che c'è dentro le parentesi graffe rappresenta il contenuto della var body.

In questo momento dentro il nostro body c'è un Text, il Text è un Component di SwiftUI ed essendo una View può essere inserito dentro il body della ContentView.

📌 Regola: Ogni View deve obbligatoriamente avere una var body per essere creata ed utilizzata.

Creare una nuova var

Adesso che sappiamo che dentro ad una variabile possiamo inserire un pezzo di interfaccia, proviamo a crearne una nuova.

Subito sotto la var body, ovvero sotto la sua parentesi graffa, aggiungi una nuova var. Chiamiamo questa var myText e come tipo di dato usiamo Text invece che some View:

var myText: Text {
   Text("My new Text")
}

Cosa cambia adesso che abbiamo usato il Text invece che il some View?

Mentre some View ci permette di utilizzare qualsiasi tipo di View, specificando Text siamo obbligati ad usare solamente quello. Infatti, se aggiungi il padding() vedrai che Xcode ti segnalerà un errore:

🚨 Cannot convert return expression of type 'some View' to return type 'Text'

Nello specifico, aggiungere il padding (vedremo meglio cosa fa nella prossima lezione), modifica il Text trasformandolo in una some View (puoi leggerlo "generica View") ma dato che la var myText vuole un Text ecco che Xcode ci blocca dall'eseguire il codice e ci segnala l'errore.

Vedremo l'importanza di specificare il type corretto nelle prossime lezioni, oggi ti volevo semplicemente dare un piccolo assaggio.

Quindi, rimuovi il type Text e usa invece some View e l'errore dovrebbe scomparire.

Come usare una var all'interno del body

Avrai sicuramente notato come la nuova variabile non compare all'interno della preview. Questo succede perché in SwiftUI l'unica variabile adibita al rendering è il body.

Tutto ciò che sta all'esterno non verra riportato all'interno del canvas e di conseguenza dell'app.

Quindi, come facciamo ad usare quella var myText?

La label di una variabile può essere passata all'interno di un'altra.

Infatti, se rimuovi il Text dal body e metti myText, vedrai che SwiftUI prenderà il contenuto di quella variabile e lo passerà su schermo:

⚠️ Nel caso in cui il Canvas dovesse mostrare un messaggio che recita: Automatic preview updating paused, clicca su Resume per farlo ripartire.

Creare nuove variabili di tipo some View all'interno delle tue view sarà uno dei tanti modi che ti permetterà di organizzare il codice sopratutto quando le tue interfacce cominceranno a contenere diversi componenti.

VStack

Adesso che abbiamo capito come funziona il body e come creare una nuova variabile che contiene una View, vediamo il primo nuovo componente chiamato VStack o Vertical Stack.

Una VStack è un contenitore verticale di View. La sintassi è relativamente semplice. VStack parentesi graffe con all'interno le view che vuoi posizione in linea verticale:

VStack {
   viewA
   viewB
   ...
} 

Vediamo subito come utilizzare questa VStack.
Inserisci all'interno del body la VStack con all'interno il myText più un nuovo Text:

var body: some View {
    VStack {
        Text("This is a VStack")
        myText
    }
}

⚠️ Nel Text che ho inserito dentro la VStack non ho messo la .padding(), per il momento non è importante ma come penso si possa capire aggiunge un po' di margine su tutti i lati della view. Vedremo più nel dettaglio nelle prossime lezioni.

Abbastanza intuitiva questa VStack no? Eventualmente lascia un commento in fondo alla lezione. 

Spacer

Al momento questa VStack è posizionata al centro dello schermo. Diciamo non un bel vedere. Per fortuna esiste un componente chiamato Spacer che ti permetterà di occupare lo spazio non usato verticalmente o orizzontalmente.

Più facile a farsi che a dirsi.

Puoi aggiungere lo spacer dentro la tua VStack creandolo utilizzando questa sintassi:

Spacer()

Et voilà! Tutto viene spostato verso l'alto e lo Spacer occupa lo spazio non utilizzato.

🙋‍♂️ Question A: Cosa succede se sposti lo Spacer tra il Text ed il myText?

HStack

Se la VStack permette di arrangiare elementi in verticale, la HStack o Horizontal Stack ci permetterà di farlo in orizzontale.

HStack { 
   viewA 
   viewB
}

Proviamo a metterla all'interno della VStack subito dopo la myText ed aggiungiamo 3 Text al suo interno:

VStack {
    Text("This is a VStack")
    myText
    HStack {
        Text("Tag1")
        Text("Tag2")
        Text("Tag3")
    }
    Spacer()
}

Ovviamente, nessuno ti vieta di innestare VStack con HStack o viceversa. Grazie a questi due elementi puoi ipoteticamente creare qualsiasi tipo di layout.

💡 Tip: Puoi mettere uno Spacer a destra o sinistra della HStack per spostare gli elementi nella direzione opposta.

Bonus: Padding e clean code

Infine, riorganizziamo leggermente il codice e puliamo il contenuto della VStack in modo tale da avere un codice un po' più snello e facile da leggere. 

💡 Tip: È una buona prassi di SwiftUI quella di lasciare il body quanto più clean possible in modo che quando ritorni su questo file ti verrà più semplice capirne il suo contenuto.

Potremmo infatti:

  1. creare una nuova var chiamta header per visualizzare i primi due Text. Ricordati di metterli dentro una nuova VStack.

  2. Ed una var chiamata stacks in cui metter la HStack.

  3. Queste etichette le sto scegliendo io immaginando che l'app avrà un header e dei tags. Ovviamente tu puoi decidere di chiamare queste variabli come ti pare, anche ciccio e caio 😂

Ed infine, usiamo quel famoso .padding() sulla VStack contenuto dentro l'header in modo tale da creare un po' di spazio tra l'header ed i tags.

VStack {
   Text("This is a VStack")
   Text("My new Text!")
}
.padding()

Comunque non preoccuparti il padding() ed altre di queste funzionalità le vedremo nel dettaglio nella prossima lezione. 

Stack Alignment

Al momento tutti gli elementi che abbiamo posizionato dentro una Stack vengono posizionati al centro ed ovviamente, in certi layout, non è del tutto conveniente.

Per fortuna, la VStack o la HStack può essere inizializzata (risentirai questo termine più in là) definendo il tipo di allineamento da utilizzare.

Come?

Ti basta aggiungere le parenti tonde subito dopo il nome del component per poi scrivere all'interno "alignment: .leading":

VStack(alignment: .leading) { 
   
}

Devo per forza usare il punto?

Yes. Il punto nel linguaggio Swift, in questo caso, puoi leggerlo come "voglio utilizzare". Nell'esempio del leading puoi leggere la linea come: Crea una VStack con alignment di tipo leading (sulla sinistra).

I valori di alignment per una VStack sono:

  1. leading: sinistra

  2. center

  3. trailing: destra

VStack(alignment: .leading) {
    Text("Hello")
    
    /// HStack necessaria per espandere
    /// la view su tutto l'asse orizzontale
    HStack {
        Spacer()
    }
    
    Spacer()
}.padding()

🚨 Nota come nell'esempio ho dovuto aggiungere una HStack con Spacer per far in modo che la VStack occupasse tutto lo spazio orizzontale. Senza questo piccolo trucco anche con allineamento leading il Text sarebbe stato renderizzato al centro. Prova a rimuovere la HStack e vedi che succede.

Se per la VStack l'allineamento influisce sull'asse orizzontale, per la HStack è l'opposto. Infatti potrai utilizzare:

  1. center

  2. top e bottom

  3. firstTextBaseline: allinea tutti gli elementi sulla linea inferiore della prima view della stack.

  4. lastTextBaseline: l'opposto del first.

HStack(alignment: .bottom) {
    Text("Hello,")
        .padding()
    
    Text("Giuseppe")
}

In questo esempio, il primo Text ha del padding che allunga la HStack in verticale, con l'allineamento di tipo .bottom gli altri elementi vengono portato sulla linea inferiore della stack. 

Ad ogni modo, non preoccuparti, vedremo meglio come utilizzare questi attributi nelle prossime lezioni.

Spacing

Infine, l'ultimo attributo di una VStack ed HStack che ti voglio mostrare si chiama Spacing e permette di definire lo spazio tra gli elementi della stack.

È abbastanza intuitivo da usare e funziona esattamente come l'alignment. All'interno delle parentesi tonde ti basta aggiungere "spacing: numero". Esempio:

HStack(spacing: 40) {
    Text("Hello,")
    Text("Giuseppe")
}

I due Text verranno divisi da 40 punti di spazio.

Nel caso in cui volessi usare alignment e spacing allo stesso momento, prima inserisci l'alignment ed infine lo spacing. Dividi i due attributi con una virgola:

HStack(alignment: .center, spacing: 40) 

Lo stesso potrai fare per la VStack.

Esercizio

Prima di lasciarci voglio metterti alla prova con un piccolo esercizio dove dovrai combinare Stack tra loro. Quello che devi fare è provare a ricreare il seguente layout:

Nel caso in cui dovessi avere qualche problema puoi trovare la soluzione in questo gist su Github

Conclusione

VStack ed HStack ti accompagneranno da qui fino alla fine dei tuoi giorni 😂. Sono tra i componenti di SwiftUI che permettono di organizzare il layout della tua app e di conseguenza li ritroverai un po' ovunque.

Noi li abbiamo utilizzati usando Text ma come puoi ben immaginare possono contenere qualsiasi tipo di View e possono anche essere combinati tra loro. Infatti, spesso e volentieri, ti ritroverai a mettere VStack dentro HStack o viceversa per poter ottenere le UI più complesse.

Nella prossima lezione parleremo di Modifier ovvero di funzioni speciali di SwiftUI che permettono di applicare degli stili alle tue view.

Uno di questi è per l'appunto quel famoso padding() che abbiamo visto fin dalla prima lezione e dalla lezione successiva finalmente capire come funziona.

Buona programmazione! 👨‍💻👩‍💻