Layouts en SwiftUI

Layouts en SwiftUI

Introduction aux Layouts

Dans SwiftUI, le concept de layout se réfère au protocole utilisé pour organiser les interfaces utilisateurs. Les layouts définissent la manière dont les différentes vues sont disposées les unes par rapport aux autres. Il est possible de créer des layouts personnalisés ainsi que des layouts conditionnels. De plus, il existe des layouts intégrés qui peuvent être utilisés lors de la création de layouts conditionnels.

Création de Layouts Personnalisés

Les layouts personnalisés sont utiles lorsque les layouts et vues intégrés ne répondent pas aux besoins spécifiques d'une application. Pour définir un layout personnalisé, vous devez implanter les méthodes ".sizeThatFits()" et ".placeSubviews()", qui sont obligatoires pour se conformer au protocole Layout :

struct MyCustomLayout: Layout {
    func sizeThatFits(
        proposal: ProposedViewSize,
        subviews: Subviews,
        cache: inout Void
    ) -> CGSize {
        // Code personnalisé pour calculer et retourner la taille du conteneur du layout.
    }

    func placeSubviews(
        in bounds: CGRect,
        proposal: ProposedViewSize,
        subviews: Subviews,
        cache: inout Void
    ) {
        // Code personnalisé pour disposer les sous-vues.
    }
}

Utilisation de Layouts Personnalisés

Les layouts personnalisés peuvent être utilisés de la même manière que d'autres conteneurs de vues, tels que HStack. Pour les utiliser, il vous suffit d'inclure les vues entre accolades après le nom du layout :

MyCustomLayout {
  // Ajoutez vos vues ici.
}

Exemple de Layout Personnalisé

Voici un exemple de layout personnalisé appelé "SpiralLayout" qui organise ses vues en spirale :

struct SpiralLayout: Layout {
    func sizeThatFits(
        proposal: ProposedViewSize,
        subviews: Subviews,
        cache: inout Void
    ) -> CGSize {
        // Utiliser tout l'espace disponible.
        proposal.replacingUnspecifiedDimensions()
    }

    func placeSubviews(
        in bounds: CGRect,
        proposal: ProposedViewSize,
        subviews: Subviews,
        cache: inout Void
    ) {
        // Déterminer le rayon pour s'adapter à l'espace disponible.
        let radius = min(bounds.size.width, bounds.size.height) / 2.0
        // Calculer l'angle pour chaque vue, selon le nombre total de vues.
        let angle = Angle.degrees(360.0 / Double(subviews.count)).radians
        // Disposer chaque vue autour du centre de l'espace avec un rayon décroissant pour créer un effet de spirale.
        for (index, subview) in subviews.enumerated() {
            var place = CGPoint(x: 0, y: -radius * CGFloat(Float(index)) / 10)
                .applying(CGAffineTransform(
                    rotationAngle: angle * Double(index)
                ))
            place.x += bounds.midX
            place.y += bounds.midY
            subview.place(at: place, anchor: .center, proposal: .unspecified)
        }
    }
}

Layouts Conditionnels

Les layouts conditionnels peuvent changer dynamiquement. Par exemple, si l'espace disponible diminue, il est possible de passer automatiquement à un layout plus concis. Voici comment déclencher la création d'un layout conditionnel :

// Déclaration d'une variable qui renvoie un layout spécifique.
// Si une condition est vraie, un layout est retourné, sinon un autre layout est fourni.
let MyLayout = myCondition ? AnyLayout(SomeLayout()) : AnyLayout(AnotherLayout())

MyLayout {
    // Ajoutez les sous-vues ici.
}

Exemple de Layout Conditionnel

Dans cet exemple, la variable "isVertical" détermine l'utilisation d'un "VStack" ou d'un "HStack", en fonction de la valeur de la variable :

@State private var isVertical = false
var body: some View {
    let layout = isVertical ? AnyLayout(VStack()) : AnyLayout(HStack())
    VStack {
        Toggle("Switch to Vertical", isOn: $isVertical.animation()).font(.title2)
        Spacer()
        layout {
            ForEach(0..<6) { i in
                RoundedRectangle(cornerRadius: 5)
                    .fill(Color.green)
                    .frame(width: 50, height: 50)
            }
        }
    }
    .padding()
}

Conclusion

Les layouts en SwiftUI offrent une flexibilité incroyable pour créer des interfaces utilisateurs adaptées à diverses conditions et besoins. En maîtrisant les concepts de layouts personnalisés et conditionnels, les développeurs peuvent concevoir des applications plus élégantes et réactives.