Modifiers: Font, Padding, Background in SwiftUI
I modifiers in SwiftUI offrono un modo semplice ed intuitivo per arricchire le tue View con stili ed attributi che ti aiuteranno a creare UI accattivanti.
Un modifier, come la parola suggerisce, è un modificatore di View
. Dietro le quinte prende la View, gli applica delle modifiche e la restituisce al Canvas già modificata. Tu dovrai solamente preoccuparti di utilizzare il modifier corretto, al resto ci pensa SwiftUI.
Infatti, grazie ai Modifier, potrai cambiare il Font dei tuoi Text
, arrotondare View
, aggiungere un Background
o cambiare il colore delle tue view (ed ovviamente la lista non si ferma qui).
Alla fine di questa lezione sarai in grado di padroneggiare un primo set di modifiers che ti permetteranno di creare layout del genere:
Excited 😍?
Allora crea un nuovo progetto iOS in SwiftUI e diamoci dentro!
Struttura di una Modifier
Un Modifier in SwiftUI è una funzione che prende in input la View, gli applica delle modifiche e la restituisce in output modificata:
Immagina una funzione in Swift come un forno in cucina. Tu sai che mettendogli qualcosa dentro, e dopo averlo acceso e settato la temperatura (molto importante 😂), ti restuisce una pietanza riscaldata o cucinata.
Se potessimo trasformare il forno in una funzione in programmazione potremmo dire che ha in input la pietanza da cucinare e la temperatura ed in output il piatto cucinato.
Nel linguaggio Swift le funzioni si scrivono utilizzando la parola func (un po' come var abbiamo scoperta crea variabili) e conclude con una lista di input tra parentesi tonde ed una freccia con la tipologia di output che restituirà:
func bake(temperature: Number, plate: Plate) -> Plate {
// Do something with the plate
return plate
}
So che sono andato un po' veloce. Le funzioni in Swift saranno un argomento che tratteremo nel dettaglio nelle prossime lezioni. Per il momento mi interessava solamente accennarti l'argomento per farti capire il dietro le quinte di un modifier.
Font e Weight
Partiamo dalla barra superiore che chiameremo bannerView, crea una nuova var di tipo some View ed al suo interno aggiungi una HStack con due Text separati da uno Spacer. Poi passa la bannerView dentro il body:
var bannerView: some View {
HStack {
Text("Modifiers")
Spacer()
Text("more")
}
}
🤔 Peppe, che lingua stai parlando? Se
HStack
,var
eSpacer
ti suonano nuovi, molto probabilmente non hai seguito la lezione precedente. Se sei qui per la prima volta dai anche un'occhiata al corso SwiftUI Tour.
Adesso diamo un po' di carattere a questi Text
assegnandogli un font.
Come?
Una View
fornisce un set di funzionalità o funzioni che possiamo utilizzare per arricchirla. Puoi accedere a queste funzioni scrivendo il simbolo punto .
dopo il nome di una View
o variabile:
Tutte quelle voci con il simbolo M
sono i modifiers
che potrai utilizzare (anche se quella M
sta ad indicare Methods
che è l'equivalente di funzione).
Se scrivi .font
subito dopo il punto vedrai comparire un menu del genere e la prima voce è il modifier che utilizzeremo:
Nella parte inferiore del pannello trovi quello che comunemente viene chiamato signature del metodo/funzione. Nel caso di font è:
func font(_ font: Font?) -> Text
Nel paragrafo precedente ti ho parlato della sintassi di una modifier/funzione ed in questo caso capiamo che:
-
func font
ci fa capire che è una funzione ed il suo nome èfont
.Quando la utilizzi non c'è bisogno di scrivere
func
.
-
(_ font: Font?)
dentro le parenti tonde c'è la lista degli argomenti. In questo caso uno solo che si chiamafont
e vuole un oggetto di tipoFont
.Il punto interrogativo dopo
Font?
sta ad indicare che l'input èOptional
o opzionale. Capire meglio quali sono le implicazioni più in là.Font
, un po' comeText
,View
,HStack
etc è una parola di SwiftUI e come puoi immaginare fornisce accesso ai font.
-
Infine la freccia
-> Text
ci fa capire che il metodo restituirà ilText
, su cui lo stiamo utilizzando, con il font applicato.Come per
func
la freccia non va scritta quando si utilizza, ci fa solo capire cosa farà il metodo.
Proviamo ad usarlo?
SwiftUI fornisce una lista di font di default e questi sono accessibili scrivendo Font.nomeFont
:
Font.nomeFont
// esempio
Font.title
Font.subtitle
// etc
Quindi all'interno del modifier scriverai:
Text("Modifiers")
.font(Font.title)
// oppure puoi omettere Font e scrivere
Text("Modifiers")
.font(.title)
Se applichi il font title questo è quello che dovrebbe apparire:
👋 Prima di andare avanti, prova ad utilizzare altri tipi di font come per esempio headline, caption o body.
Per concludere questa sezione, il modifier fontWeight
permette di aggiungere o rimuovere variazioni di grassetto. Quindi usalo sul Text
subito dopo il font selezionando il weight
di tipo bold
:
Text("Modifiers")
.font(.title)
.fontWeight(.bold)
Il tipo di dato del fontWeight
modifier fa parte del tipo Font
. Infatti, la sua sintassi è Font.Weight
ovvero Weight
ha senso solamente nel contesto del Font
. Quindi puoi scrivere il valore in queste due sintassi:
fontWeight(Font.Weight.light)
fontWeight(.medium)
Generalmente si utilizza la contratta, ovvero punto ed opzione che vuoi utilizzare.
Accenno di Opzionalità
Quando abbiamo provato ad usare il modifier fontWeight
o lo stesso font
abbiamo notato che il type aveva uno strano punto interrogativo alla fine:
func font(_ font: Font?) -> View
func fontWeight(_ weight: Font.Weight?) -> View
Il punto interrogativo, dopo il nome di un type, esempio: CGFloat?
, View?
, Font?
etc sta ad indicare che il valore può essere opzionale.
Optional
per il linguaggio Swift è un tipo di dato particolare che può avere due valori:
nil
o un valore appartenete al type.
Per SwiftUI, quando passeremo nil
ad un modifier stiamo ad indicare che vogliamo utilizzare il valore di default del modificatore.
Text("hello")
.font(nil)
.fontWeight(nil)
In pratica è un po' come annullare l'effetto del modificatore. In genere si utilizza un valore Optional
in situazioni dove, per esempio:
Al cliccare di un bottone vogliamo annullare una serie di effetti ad una
View
.Dobbiamo eseguire il download di una lista di ricette e ci vuole del tempo per farlo, quindi la variabile partirà con il valore
nil
` e poi gli assegneremo il valore non appena la lista è stata scaricata.Vogliamo scaricare un'immagine e conservarla in una
var
. Questa parte con nil e quando il download finisce passeremo l'immagine in questione.
Scenderemo nei dettagli dell'opzionalità nel prossimi moduli, per il momento era importante accennarti cosa fa dato che incontrerai questo punto interrogativo in moltissimi modifier.
Background
Una volta capito come utilizzare un modifier gli altri vengono quasi di conseguenza. Uno dei pochi che però richiede un po' di attenzione in più è il modifier background
.
Il modifier background
permette di aggiungere uno stile o una nuova view come sfondo della view su cui viene utilizzato.
Se infatti provi ad utilizzarlo sulla bannerView
vedrai che la lista dei metodi ti suggerisce diverse opzioni:
Al momento quello su cui voglio focalizzarmi è il modifier che ci permetterà di settare uno style o una Shape al nostro background:
func background(_ style: ShapeStyle, in shape: Shape) -> View
/// oppure solo style
func background(_ style: ShapeStyle) -> View
// o solo shape
func background(in shape: Shape) -> View
Uno dei primi style che imparerai ad utilizzare è il Color
.
In SwiftUI i colori vengono categorizzati come view e style. Di conseguenza, potrai utilizzare un colore come sfondo di un'altra view.
SwiftUI fornisce dei colori di default che sono accessibili utilizzando la sintassi Color.nomeColore
:
Color.red
Colore.orange
Color.gray
Color.blue
....
Di conseguenza, proviamo ad applicare il Color.orange come background della bannerView:
var bannerView: some View {
HStack {
Text("Modifiers")
.font(.title)
.fontWeight(.bold)
Spacer()
Text("more")
}
.background(Color.orange)
}
💡 Aggiungi il modifier padding prima del
background
per creare un po' di spazio tra il contenuto dellaHStack
ed ilbackground
.
Ora, immaginiamo di voler arrontondare i bordi di questo header. Ci sono due modi per farlo:
Aggiungere un altro modifier, subito dopo il
background
, chiamatocornerRadius
.Oppure utilizzare la
Shape
RoundedRectangle
come valore del modifierbackground
.
Il modifier cornerRadius
vuole come primo parametro un valore di radius
di tipo CGFloat
ovvero un numero con o senza virgola:
func cornerRadius(_ radius: CGFloat) -> View
Oppure, puoi ottenere lo stesso risultato in una singola istruzione, utilizzando la shape RoundedRectangle
:
RoundedRectangle(cornerRadius: CGFloat)
direttamente sul modifier background
:
.background(
RoundedRectangle(cornerRadius: 8)
)
Di default vedrai che la shape è di colore nero. Per cambiarlo, aggiungi il modifier fill(Color.nomeColore)
alla RoundedRectangle
:
.background(
RoundedRectangle(cornerRadius: 8)
.fill(Color.orange)
)
Quale delle due opzioni utilizzare? 🤔
Entrambe le sintassi sono più o meno equivalenti e producono lo stesso risultato.
Vedrai sempre più spesso che in programmazione non esiste un'unica via per risolvere un problema. Anzi, tutto il contrario. Quando troveremo modi diversi di fare le cose proverò ad evidenziare le differenze in modo tale che tu possa applicare la soluzione ottimale in base al problema che stai affrondando.
In questo caso, però, non c'è una vera e propria differenza tra usare il borderRadius
ed il RoundedRectangle
dato che quest'ultimo fa uso della stessa logica che il borderRadius
utilizza per arrotondare i bordi.
ForegroundColor
Abbiamo visto come assegnare un colore al background. Ma come possiamo cambiare colore al Text
?
La soluzione è il modifier foregroundColor
. Il foregroundColor
può essere applicato su elementi che contengono testo, quindi anche altri componenti rispetto al Text
, e su container come VSTack
e HStack
per assegnare il colore a tutti gli elementi che contengono:
foregroundColor(_ color: Color?) -> View
Per esempio, nella nostra bannerView
, potremmo cambiare il colore dei due Text
o assegnando il foregroundColor
ad ognuna di loro, oppure direttamente alla stack che li contiene:
HStack {
Text("Modifiers")
.font(.title)
.fontWeight(.bold)
Spacer()
Text("more")
}
.foregroundColor(.white) // o Color.white è equivalente
// oppure
HStack {
Text("Modifiers")
.font(.title)
.fontWeight(.bold)
.foregroundColor(.white)
Spacer()
Text("more")
.foregroundColor(.white.opacity(0.8))
}
.padding()
Nel caso in cui volessi modificare l'opacità di un Color
per renderlo quindi trasparente, ti basta aggiungere il modifier opacity
al colore in questione:
Color.red.opacity(0.5) // 50%
Il valore di opacity
è un numero con virgola che va da 0 ad 1. 1 rappresenta 100% quindi no opacità, e l'estremo inferiore, quindi 0.0 sarà totalmente trasparente:
func opacity(_ opacity: Double) -> Color
✅
Double
è il type che nel linguaggio Swift rappresenta valore in virgola.CGFloat
, che abbiamo visto nelcornerRadius
e tra poco nel modifierpadding
, è un valore equivalente o sinonimo delDouble
.
L'unica differenza sostanziale è che ilCGFloat
è utilizzato per operazione grafiche, infatti significa:Core Grafic Float
.
Padding
Concludiamo in bellezza questa lezione parlando del modifier che ci portiamo dall'inizio del corso: padding
. Il modifier padding
in SwiftUI permette di distanziare i confini di una view.
Di default distanzia tutti e quattro i lati ma abbiamo la possibilità di attivare il padding
su uno o più lati specificando un valore del tipo Edge.set
:
padding(_ edges: Edge.Set, length: CGFloat?)
Dove i valori di Edge.Set
sono:
Edge.Set.leading
.trailing
.top
.bottom
.leading
.vertical
.horizontal
.all
Trailing
e leading
li abbiamo già incontrati quando abbiamo parlato di alignment
per la StackView
e significano trailing/destra e leading/sinistra. vertical
ed horizontal
permettono di modificare contemporaneamente top/bottom o leading/trailing rispettivamente.
Di default edges
è sempre settato su .all
.
Nel caso in cui volessi modificare solamente un lato con una distanza ben specifica, allora scriverai:
.padding(.top, 30)
Mentre, se volessi modificare più di un lato ed usare lo stesso valore, allora ti basterà mettere gli Edge
all'interno di parantesi quadre:
.padding([.top, bottom], 20)
Ed infine, se volessi modificare i lati con diversi valori, nessuno ti vieta di aggiungere più di un padding
alla tua view:
myView
.padding(.horizontal, 40)
.padding(.bottom, 20)
Se riportiamo queste nozioni al nostro progetto ed aggiungiamo una semplice VStack
sotto la bannerView
ed utilizziamo due padding top/bottom
:
var welcomeView: some View {
VStack(alignment: .leading, spacing: 5) {
Text("Hi 👋")
.font(.title2)
Text("Giuseppe")
.font(.title3)
}
.padding(.top, 20)
.padding(.bottom, 30)
}
Esercizio
Adesso che abbiamo in canna alcuni dei modifier fondamentali lascio a te il compito di completare il layout della lezione:
Nel caso avessi avuto qualche problema, o vuoi confrontarlo con la soluzione, qui trovi il codice completo.
Conclusione
Ci siamo, adesso sappiamo che SwiftUI contiene una libreria di componenti e modifiers. Finora abbiamo incontrato componenti che si comportano da contenitore, come VStack
ed HStack
ed altri che rappresentano informazioni come il Text
.
Tutti i componenti in SwiftUI offrono dei modifiers che ne permettono di alterarne il normale look and feel.
Nella prossima lezione, daremo un'occhiata al componente Image
prima di passare alle basi della programmazione Swift per comprendere fino in fondo il codice che stiamo scrivendo.
Buona programmazione!