0Pricing
Swift Academy · Leçon

Créer une mise en page fluide

Répartissez dynamiquement les éléments sur plusieurs lignes.

Créer une mise en page fluide est une leçon Swift Academy gratuite sur CoddyKit. Ceci est la leçon 3 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.

Qu’est-ce qu’un agencement en flux ?

Un agencement en flux place les éléments de gauche à droite et les renvoie à la ligne suivante lorsque l’élément suivant dépasserait la largeur disponible, comme pour des pastilles d’étiquettes ou un retour à la ligne automatique.

Le plan

Nous calculerons les sauts de ligne dans une fonction auxiliaire partagée, renverrons la hauteur totale depuis sizeThatFits et réutiliserons le même calcul dans placeSubviews. Le partage de la logique garantit la cohérence entre les deux méthodes.

Modélisation d’un placement

Une petite structure mémorise l’emplacement de chaque sous-vue. Calculer tous les placements à l’avance rend les deux méthodes du protocole triviales.

struct Placement {
    let index: Int
    let point: CGPoint
    let size: CGSize
}

L’algorithme de retour à la ligne

Parcourez les sous-vues en suivant la position x actuelle. Si un enfant dépasse la largeur maximale, réinitialisez x et descendez de la hauteur de la ligne plus l’espacement.

func layout(_ subviews: Subviews, maxWidth: CGFloat) -> (placements: [Placement], height: CGFloat) {
    var placements: [Placement] = []
    var x: CGFloat = 0, y: CGFloat = 0, rowHeight: CGFloat = 0
    let spacing: CGFloat = 8
    for (i, s) in subviews.enumerated() {
        let size = s.sizeThatFits(.unspecified)
        if x + size.width > maxWidth, x > 0 {
            x = 0; y += rowHeight + spacing; rowHeight = 0
        }
        placements.append(Placement(index: i, point: CGPoint(x: x, y: y), size: size))
        x += size.width + spacing
        rowHeight = max(rowHeight, size.height)
    }
    return (placements, y + rowHeight)
}

Implémentation de sizeThatFits

sizeThatFits exécute l’algorithme avec la largeur proposée et renvoie la largeur de la proposition ainsi que la hauteur totale calculée.

func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
    let maxWidth = proposal.width ?? .infinity
    let result = layout(subviews, maxWidth: maxWidth)
    return CGSize(width: maxWidth == .infinity ? result.placements.map { $0.point.x + $0.size.width }.max() ?? 0 : maxWidth,
                  height: result.height)
}

Implémentation de placeSubviews

placeSubviews exécute le même algorithme, décale ensuite chaque placement de bounds.origin et appelle place.

func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
    let result = layout(subviews, maxWidth: bounds.width)
    for p in result.placements {
        let pt = CGPoint(x: bounds.minX + p.point.x, y: bounds.minY + p.point.y)
        subviews[p.index].place(at: pt, anchor: .topLeading,
                                proposal: ProposedViewSize(p.size))
    }
}

Le type FlowLayout complet

La combinaison de ces éléments donne un agencement en flux complet et réutilisable. L’auxiliaire partagé layout garantit la concordance entre la taille et le placement.

struct FlowLayout: Layout {
    var spacing: CGFloat = 8
    func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
        let r = layout(subviews, maxWidth: proposal.width ?? .infinity)
        return CGSize(width: proposal.width ?? 0, height: r.height)
    }
    func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
        let r = layout(subviews, maxWidth: bounds.width)
        for p in r.placements {
            subviews[p.index].place(at: CGPoint(x: bounds.minX + p.point.x, y: bounds.minY + p.point.y),
                                    anchor: .topLeading, proposal: ProposedViewSize(p.size))
        }
    }
}

Utilisation de l’agencement en flux

Intégrez-le comme n’importe quel conteneur. Les étiquettes passent automatiquement à la ligne lorsque la largeur diminue.

var body: some View {
    FlowLayout {
        ForEach(tags, id: \.self) { tag in
            Text(tag)
                .padding(8)
                .background(.blue.opacity(0.2))
                .clipShape(Capsule())
        }
    }
}

Gestion du premier élément de chaque ligne

La condition x > 0 empêche le retour à la ligne avant le premier élément d’une ligne. Sans elle, un élément plus large que le conteneur pourrait provoquer une boucle infinie ou être inutilement placé sur une ligne vide.

if x + size.width > maxWidth, x > 0 {
    // wrap only if the row already has content
}

Choix de l’espacement

Ici, l’espacement est une propriété stockée avec une valeur par défaut. En production, lisez la préférence d’spacing de chaque sous-vue afin de respecter les métriques du système plutôt qu’une constante codée en dur.

var spacing: CGFloat = 8 // configurable per instance

Test des cas limites

Testez avec zéro élément, un élément géant et de nombreux éléments minuscules. Un agencement en flux correct indique une hauteur nulle pour un contenu vide et ne rogne jamais un unique enfant trop grand.

Vérification rapide : agencement en flux

Vérifiez votre compréhension de l’algorithme de retour à la ligne.

Récapitulatif : créer un agencement en flux

Un agencement en flux fait passer les éléments à la ligne en suivant la position x courante et en la réinitialisant sur une nouvelle ligne lorsque l’enfant suivant dépasserait la largeur disponible. Une fonction auxiliaire partagée calcule tous les placements et la hauteur totale, afin que sizeThatFits et placeSubviews restent cohérents.

Décalez les placements de bounds.origin, gérez le premier élément de chaque ligne et testez les cas vide, trop grand et comportant de nombreux éléments. Vous obtenez ainsi un conteneur réutilisable avec retour à la ligne.

Questions Fréquemment Posées

La leçon « Créer une mise en page fluide » est-elle gratuite ?

Oui — le texte complet de « Créer une mise en page fluide » 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 « Créer une mise en page fluide » ?

Répartissez dynamiquement les éléments sur plusieurs lignes. 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 3 sur 4.

Combien de temps prend la leçon « Créer une mise en page fluide » ?

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