Pain au chocolat ou chocolatine ? React ou Vue ? Tennant ou Capaldi ?

Ce genre de dilemme sans bonne réponse est présent dans tous les domaines. Et quand on parle de développement iOS il y en avait un gros: storyboard ou code. Deux façons de gérer ses interfaces, chacune avec ses pros et ses cons. Quand arriva un véritable game changer qui mit tout le monde d’accord: SwiftUI ! Nous allons donc aujourd’hui voir comment faire de l’intégration, mais cette fois en Swift !

Mais qu’est-ce donc que cette chose là, dis-donc ?

Swift UI est un nouveau framework lancé par Apple afin de développer les interfaces en utilisant une syntaxe déclarative pour décrire le comportement de notre interface. En clair, vous contrôlez intégralement votre interface avec du code. Besoin de rajouter du padding ? Appelez la fonction padding sur votre élément. Vous voulez aligner trois éléments ? Créer une stack horizontale et mettez vos éléments dedans. Et le plus beau dans tout ça c’est qu’il est prévu pour s’intégrer facilement avec de vieilles applications. Si vous avez envie de créer de nouvelles interfaces ou de modifier d’anciennes, vous pouvez donc passer par SwiftUI Même si votre projet date d’avant !

Pour faire court, si vous voulez afficher du texte, appelez la fonction Text(« Votre text »). Par la suite, si vous avez besoin de changer la couleur de police en rouge, vous pouvez appeler .foregroundColor(.red). Puis pour ajouter du padding, appelez la fonction .padding(20). Et hop, vous avez un texte rouge avec 20px de padding. Facile ? Effectivement, mais voyons ça plus en détail au travers d’un petit projet !

Initier un projet

Commençons donc directement notre projet, puisque c’est pour ça que nous sommes là ! Ouvrez-donc Xcode, cliquez sur « créer un nouveau projet Xcode » puis choisissez « App » dans la partie iOS. Ensuite vous pouvez remplir les informations de l’app que nous voulons créer, pensez juste bien à choisir « SwiftUI » dans la partie « Interface » et « Swift » dans la partie « Language« .

Créer un projet xcode
Choisissez « Create a new Xcode project »
Choix de l'app
Choisissez « App » dans « iOS »
Choix de SwiftUI
Soyez sûrs de bien choisir « SwiftUI »

Une fois l’app créée, Xcode va vous générer plusieurs fichiers. Pour ce tutoriel nous n’allons en utiliser qu’un parmi ceux-là: ContentView.

Ouvez-le, et vous devriez voir deux choses: votre code sur la partie gauche de l’interface et votre rendu sur le simulateur à droite.

L'interface Xcode

Parlons peu, parlons code

Dans notre ContentView, nous observons deux choses. Premièrement nous avons un struct qui définit notre vue, ensuite nous avons une preview. Cette preview est ce qui permet de générer la vue du simulateur à droite. Elle permet de tester aussi bien des vues complètes comme là que des components qui attendent des arguments. Nous verrons tout ça plus tard.

Pour l’heure, attelons nous déjà à créer la base de notre vue et ajouter le principal: un background !

Pour ce faire il existe de nombreuses méthodes. L’une d’entre elle est d’utiliser un objet color qui contiendra toute notre interface et qui évitera les « safearea » (l’encoche et les informations d’heure/réseau/batterie). Et pour notre conteneur principal nous allons utiliser un VStack, c’est à dire un conteneur qui alignera tous ses enfants horizontalement.

struct ContentView: View {
    var body: some View {
        Color(.black)
        .ignoresSafeArea()
        .overlay(
            VStack {}
        )
    }
}

Ici, dans notre body nous créons d’abord un objet Color() avec en paramètre une couleur. Nous appelons ensuite la fonction ignoresSafeArea qui lui permettra de monter jusqu’en haut de notre vue et donc ne pas avoir de fond blanc à cet endroit, puis la fonction overlay qui contiendra le reste de notre vue. À l’interieur nous pouvons créer notre vrai conteneur: un VStack !

Gestion des couleurs

Bon, par contre je suis gêné. J’ai un fond noir mais je veux une application verte. Ici le meilleur moyen de créer quelque chose de propre c’est d’ajouter des couleurs globales. Ainsi, si vous avez besoin de modifier votre charte graphique, il suffit de mettre à jour une zone du code pour tout impacter.

Pour ce faire, rendez-vous dans la partie « Assets« . Faites un clic droit dans la liste des assets puis choisissez « New Color Set« . Nommez-le greenBg (ou un nom plus classe si vous préferez).

Creer un color set
Creer un color set

Vous verrez alors deux items dans votre colorSet: un pour l’apparence par défaut, et un pour le mode sombre. Cliquez sur un d’entre eux, et dans la partie à droite des propriétés, choisissez « 8-bit Hexadecimal » en tant qu’Input method puis entrez la couleur #014550.

Créer une couleur

Tant que nous sommes là, ajoutez:

  • darkBg: #10262F
  • lightBg: #1A5A62
  • darkGrey: #2B3B42
  • lightGrey: #404E55

Nous avons désormais de superbes couleurs prêtes à l’emploi. Dans notre ContentView, changeons le Color(.dark) par:

Color("greenBg")

Et voilà ! Vous avez changé le fond de votre vue avec une couleur custom 👏🏻👏🏻

Commençons par l’en-tête

l'en-tête
L’en-tête

Déjà, pour des raisons que l’on expliquera plus tard, nous allons aussi enfermer notre en-tête dans son propre VStack (oui on peut), commençons donc par ajouter un VStack dans notre VStack. À l’interieur nous allons créer une HStack pour afficher tous nos éléments les uns à côté des autres: l’image, nos textes et nos deux boutons.

Pour l’image, je vous laisse ajouter une image (un drag&drop suffit) dans votre onglet « Assets ». Nous allons maintenant pouvoir créer une image avec l’objet « Image() » dans laquelle nous passerons en paramètre une UIImage:

Image(uiImage: UIImage(named: "profile")!)

Sur cette image, nous allons d’abord appeler la fonction resizable() afin d’autoriser le changement de taille, ensuite nous allons l’arrondir grâce à une clipShape de type circle et enfin la resizer avec la fonction frame().

Image(uiImage: UIImage(named: "profile")!)
                            .resizable()
                            .clipShape(Circle())
                            .frame(width: 50, height: 50)

Pour nos textes, étant donné qu’ils sont l’un sur l’autre nous allons avoir besoin d’un VStack. Pour chacune des lignes nous allons donc pouvoir utiliser un objet Text(). Entre parenthèse vous pouvez préciser le texte à afficher, et tada !

Sur le premier texte, nous allons utiliser une fonction bold() et sur le second nous allons mettre une fontweight en light. Comme le light est moins courant, il n’a pas droit à sa propre fonction, mais pas d’inquiétudes ! Nous allons d’abord appeler la fonction .fontWeight() puis dedans mettre la valeur .light et le tour est joué. Vous remarquerez alors un léger soucis: les textes sont centrés dans le conteneur et donc pas alignés. Pour régler ça, ajoutons sur notre VStack le paramètre « alignment: .leading ».

VStack(alignment: .leading) {
     Text("Medrupaloscil").bold()
     Text("Fullstack dev").fontWeight(.light)
}

Et comme le texte n’est pas encore de la bonne couleur, sur notre conteneur principal (celui à la racine de notre Color), ajoutons un .foregroundColor(.white).

Ajoutons nos boutons

Pour nos boutons nous allons d’abord créer une fonction. Comme ce n’est pas le but de ce tuto, on va juste créer une fonction test() qui fait un print(« hey »):

func test() {
    print("hey")
}

Nous allons donc pouvoir créer deux boutons qui prennent cette fonction en paramètre. Dans chacun de ces boutons nous allons pouvoir ajouter des images un peu spéciales ! Depuis quelques temps existent sur vos machines Apple sans forcément que vous puissiez les voir les Symboles « SF ». Ils sont utilisables dans SwiftUI mais aussi n’importe où dans le système. Pour les trouver vous avez une app en bêta qui existe, mais pas d’inquiétudes je vous les donne !
Pour notre loupe nous allons utiliser « magnifyingglass » et pour notre cloche nous allons utiliser « bell.badge« . Mais le tout est assez petit ! Nous allons donc devoir les agrandir ! Ici encore SwiftUI n’a pas de fonction directe. Nous allons donc passer par la fonction .font(), dans laquelle nous appellerons la fonction .system() avec en paramètre une size de 25:

Button(action: test) {
    Image(systemName: "magnifyingglass")
        .font(.system(size: 25))
}
Button(action: test) {
    Image(systemName: "bell.badge")
        .font(.system(size: 25))
}

Le dernier petit soucis est que nos boutons sont collés à notre texte, nous allons juste placer un Spacer() entre les deux et voilà, l’espace disponible va automatiquement se remplir afin de séparer les éléments !

Juste un petit ajout

En dessous de notre HStack qui contient l’en-tête nous allons pouvoir ajouter le titre de la partie suivante.

Pour ce faire, commençons par écrire un Text(« October 2022 ») sur lequel nous allons ajouter déjà une fonction .bold(). Ensuite pour le séparer légèrement de l’en-tête, ajoutons un padding-top avec la fonction padding prenant en premier paramètre la valeur .top et en second la valeur 20. Ensuite ajustons la taille du texte pour la passer à 20, vous savez désormais comment faire:

Text("October 2022")
    .bold()
    .padding(.top, 20)
    .font(.system(size: 20))

Hmmm, par contre mon texte est centré là, non ? Sur son parent direct (le VStack), ajoutons en paramètre un alignment: .leading comme pour nos deux textes précédent et c’est réglé !

Créer des items réutilisables

Des components SwiftUI réutilisables

Pour la suite, nous allons avoir besoin de dupliquer un élément pour faire notre système de date. Nous allons passer par un component réutilisable qui prend des paramètres pour changer son affichage.

Pour cela, faites un clic droit sur la hiérarchie des fichiers sur la gauche et choisissez « New File ». Cliquez ensuite sur « SwiftUI View« .

Nouveau fichier SwiftUI
Nouveau fichier SwiftUI

Nommez ce component DateItem et créez-le. Au dessus de votre « var body« , nous allons ajouter trois variables: une variable date qui sera une String, une day en String et une current qui sera un Boolean avec en valeur par défaut « false« .

var date: String;
var day: String;
var current: Bool = false;

Nous allons donc devoir modifier notre preview pour ajouter ces paramètres qui sont maintenant nécessaires au bon fonctionnement de l’item. Nous allons donc en créer deux: un sans la valeur current, l’autre avec la valeur current à true afin de traiter les deux cas de figure.

struct DateItem_Previews: PreviewProvider {
    static var previews: some View {
        HStack {
            DateItem(date: "03", day: "Mon")
            DateItem(date: "04", day: "Tue", current: true)
        }
    }
}

Commençons par notre container ! Nous allons utiliser une VStack. Nous allons utiliser deux fonctions padding: une avec .horizontal en 10 et une avec .vertical en 20. Puis ajoutons deux couleurs: le background et le texte. Ces deux couleurs seront conditionnelle: si current est à true on va être en sombre sur blanc, sinon on sera en blanc sur sombre. On peut donc passer simplement par une ternaire avec par exemple: current ? Color(.white) : Color(« lightBg »). Et on ajoute aussi juste un cornerRadius à 30 pour arrondir tout ça.

VStack {
}
.padding(.vertical, 20)
.padding(.horizontal, 10)
.background( )
.foregroundColor(current ? Color("darkBg") : .white)
.cornerRadius(30)

Dans cette VStack, on peut rajouter un text qui prend date en paramètre qui sera en bold et en font-size 20. Puis un autre text qui prend day en paramètre, en light et en 13 de size.

Text(date)
    .bold()
    .font(.system(size: 20))
Text(day)
    .font(.system(size: 13))
    .fontWeight(.light)

Vous devriez désormais maintenant voir vos deux items dans votre simulateur à droite. On peut donc créer nos cinq items dans une HStack en dessous du mois d’octobre, et pour bien les espacer on peut placer un Spacer() entre chaque. On rajoute juste un léger padding sur le top. Et voilà:

HStack {
    DateItem(date: "03", day: "Mon")
    Spacer()
    DateItem(date: "04", day: "Tue")
    Spacer()
    DateItem(date: "05", day: "Wed", current: true)
    Spacer()
    DateItem(date: "06", day: "Thu")
    Spacer()
    DateItem(date: "07", day: "Fri")
}.padding(.top)

Et comme par défaut tout votre contenu va être centré, vous pouvez ajouter un Spacer() en dessous de votre VStack.

Voici donc le code complet:

import SwiftUI


func test() {
    print("hey")
}

struct ContentView: View {
    var body: some View {
        Color("greenBg")
        .ignoresSafeArea()
        .overlay(
            VStack {
                VStack(alignment: .leading) {
                    HStack {
                        Image(uiImage: UIImage(named: "profile")!)
                            .resizable()
                            .clipShape(Circle())
                            .frame(width: 50, height: 50)
                        VStack(alignment: .leading) {
                            Text("Medrupaloscil").bold()
                            Text("Fullstack dev").fontWeight(.light)
                        }
                        Spacer()
                        Button(action: test) {
                            Image(systemName: "magnifyingglass")
                                .font(.system(size: 25))
                        }
                        Button(action: test) {
                            Image(systemName: "bell.badge")
                                .font(.system(size: 25))
                        }
                    }
                    Text("October 2022")
                        .bold()
                        .padding(.top, 20)
                        .font(.system(size: 20))
                    HStack {
                        DateItem(date: "03", day: "Mon")
                        Spacer()
                        DateItem(date: "04", day: "Tue")
                        Spacer()
                        DateItem(date: "05", day: "Wed", current: true)
                        Spacer()
                        DateItem(date: "06", day: "Thu")
                        Spacer()
                        DateItem(date: "07", day: "Fri")
                    }.padding(.top)
                }
                .padding(30)
                Spacer()
            }
            .foregroundColor(.white)
        )
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
struct DateItem: View {
    var date: String;
    var day: String;
    var current: Bool = false;
    var body: some View {
        VStack {
            Text(date)
                .bold()
                .font(.system(size: 20))
            Text(day)
                .font(.system(size: 13))
                .fontWeight(.light)
        }
        .padding(.vertical, 20)
        .padding(.horizontal, 10)
        .background(current ? Color(.white) : Color("lightBg"))
        .foregroundColor(current ? Color("darkBg") : .white)
        .cornerRadius(30)
    }
}

struct DateItem_Previews: PreviewProvider {
    static var previews: some View {
        HStack {
            DateItem(date: "03", day: "Mon")
            DateItem(date: "04", day: "Tue", current: true)
        }
    }
}

Voilà pour la première partie de cette introduction. Nous nous retrouvons la semaine prochaine pour finir cette page et voir quelques fonctions supplémentaires.