0Pricing
Swift Academy · Leçon

Bases du protocole Layout

Implémentez sizeThatFits et placeSubviews.

Bases du protocole Layout est une leçon Swift Academy gratuite sur CoddyKit. Ceci est la leçon 1 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Swift Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Swift Academy comprend 4 leçons au total.

Pourquoi une disposition personnalisée ?

SwiftUI fournit HStack, VStack et ZStack, mais vous avez parfois besoin d'une logique d'agencement qu'ils ne peuvent pas exprimer : menus radiaux, dispositions avec retour à la ligne, grilles en maçonnerie.

Le protocole Layout vous permet d'écrire cette logique tout en continuant à composer des vues SwiftUI ordinaires.

Le protocole Layout

Layout exige deux méthodes : sizeThatFits (quelle doit être ma taille ?) et placeSubviews (où placer chaque enfant ?).

Vous adoptez ce protocole dans un type valeur et l'utilisez comme n'importe quelle pile intégrée.

struct MyLayout: Layout {
    func sizeThatFits(proposal: ProposedViewSize,
                      subviews: Subviews,
                      cache: inout ()) -> CGSize { .zero }
    func placeSubviews(in bounds: CGRect,
                       proposal: ProposedViewSize,
                       subviews: Subviews,
                       cache: inout ()) { }
}

Utiliser une disposition personnalisée

Une valeur Layout agit comme un conteneur. Vous lui transmettez les vues enfants dans sa fermeture finale, exactement comme pour une pile.

var body: some View {
    MyLayout {
        Text("One")
        Text("Two")
        Text("Three")
    }
}

ProposedViewSize

Le parent propose une taille à votre disposition via ProposedViewSize. Ses valeurs width et height sont facultatives : nil signifie « non spécifiée, choisissez votre taille idéale ».

Les valeurs spéciales .zero, .infinity et .unspecified permettent de sonder les tailles minimale, maximale et idéale.

func sizeThatFits(proposal: ProposedViewSize,
                  subviews: Subviews,
                  cache: inout ()) -> CGSize {
    let width = proposal.width ?? 0
    return CGSize(width: width, height: 44)
}

sizeThatFits en détail

sizeThatFits renvoie la taille souhaitée par votre disposition pour une proposition donnée. SwiftUI peut l'appeler plusieurs fois avec des propositions différentes afin de comprendre votre flexibilité.

func sizeThatFits(proposal: ProposedViewSize,
                  subviews: Subviews,
                  cache: inout ()) -> CGSize {
    // Sum child ideal sizes for a simple horizontal stack
    let sizes = subviews.map { $0.sizeThatFits(.unspecified) }
    let w = sizes.reduce(0) { $0 + $1.width }
    let h = sizes.map(\.height).max() ?? 0
    return CGSize(width: w, height: h)
}

La collection des sous-vues

Subviews est une collection de représentants pour chaque enfant. Chaque représentant répond à sizeThatFits et expose les priorités de disposition ainsi que les valeurs personnalisées.

Vous ne voyez jamais les vues réelles, uniquement ces représentants de mesure.

for subview in subviews {
    let size = subview.sizeThatFits(.unspecified)
    print(size)
}

placeSubviews

placeSubviews attribue à chaque enfant une position dans le rectangle bounds qui vous a été fourni.

Appelez place(at:anchor:proposal:) sur chaque représentant de sous-vue.

func placeSubviews(in bounds: CGRect,
                   proposal: ProposedViewSize,
                   subviews: Subviews,
                   cache: inout ()) {
    var x = bounds.minX
    for subview in subviews {
        let size = subview.sizeThatFits(.unspecified)
        subview.place(at: CGPoint(x: x, y: bounds.midY),
                      anchor: .leading,
                      proposal: .unspecified)
        x += size.width
    }
}

Ancres lors du placement

Le paramètre anchor indique quel point de l'enfant doit être placé sur la position que vous fournissez. .topLeading place l'enfant par son coin supérieur gauche ; .center le centre sur ce point.

subview.place(at: CGPoint(x: 0, y: 0),
              anchor: .topLeading,
              proposal: .unspecified)

Les limites ne commencent pas toujours à l'origine

Le rectangle bounds peut ne pas commencer en (0,0). Positionnez-vous toujours par rapport à bounds.minX et bounds.minY, jamais par rapport à zéro.

let startX = bounds.minX // not 0
let startY = bounds.minY

Une disposition minimale à espacement uniforme

Pour rassembler ces notions, voici une disposition qui place les enfants de gauche à droite sans espacement. Les deux méthodes restent cohérentes : la taille indiquée correspond au placement.

struct SimpleHStack: Layout {
    func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
        let sizes = subviews.map { $0.sizeThatFits(.unspecified) }
        return CGSize(width: sizes.reduce(0){ $0 + $1.width },
                      height: sizes.map(\.height).max() ?? 0)
    }
    func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
        var x = bounds.minX
        for s in subviews {
            let size = s.sizeThatFits(.unspecified)
            s.place(at: CGPoint(x: x, y: bounds.minY), anchor: .topLeading, proposal: .unspecified)
            x += size.width
        }
    }
}

La cohérence vous incombe

SwiftUI suppose que vos deux méthodes sont cohérentes. Si placeSubviews utilise plus d'espace que ne l'indique sizeThatFits, les enfants peuvent être tronqués ou se chevaucher.

Partagez les calculs géométriques entre les deux méthodes.

Vérification rapide : notions de base des dispositions

Vérifiez votre compréhension du protocole Layout.

Récapitulatif : notions de base du protocole Layout

Le protocole Layout transforme une logique d'agencement personnalisée en conteneur réutilisable. sizeThatFits indique votre taille pour une valeur ProposedViewSize, et placeSubviews positionne chaque représentant enfant dans bounds à l'aide de place(at:anchor:proposal:).

Les propositions contiennent des dimensions facultatives, les limites peuvent être décalées par rapport à l'origine et les deux méthodes doivent rester cohérentes géométriquement. Nous allons ensuite mesurer les sous-vues en détail.

Questions Fréquemment Posées

La leçon « Bases du protocole Layout » est-elle gratuite ?

Oui — le texte complet de « Bases du protocole Layout » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Swift Academy, passe à CoddyKit PRO. Le cours Swift Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Bases du protocole Layout » ?

Implémentez sizeThatFits et placeSubviews. Tu pratiques Swift Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer Swift Academy ?

Aucune expérience préalable n'est requise. Swift Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 4.

Combien de temps prend la leçon « Bases du protocole Layout » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon Swift Academy ?

Oui. Chaque leçon Swift Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Bases du protocole Layout
  2. Mesurer les sous-vues
  3. Créer une mise en page fluide
  4. Cache de mise en page et performances
← Retour à Swift Academy