SwiftUI – AnyLayout

By | 15/02/2023

In this post, we will see how to use the new component AnyLayout introduced in SwiftUI 4.
But first of all, what is AnyLayout?
From Apple developer web site:
“Use an AnyLayout instance to enable dynamically changing the type of a layout container without destroying the state of the subviews”
In a nutshell, with AnyLayout we can switch for example between VStack and HStack without destroying the state of the subviews.

Let’s start by opening Xcode then, we create an Single View App project and finally we add this code in ContentView.swift:

[CONTENTVIEW.SWIFT]

import SwiftUI

struct ContentView: View {
    var body: some View {
        
        VStack {
            Rectangle()
                .fill(.blue)
                .frame(width: 150, height: 150)
            Circle()
                .fill(.red)
                .frame(width: 150, height: 150)
            Capsule()
                .fill(.orange)
                .frame(width: 150, height: 100)
        }
        .padding()
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.cyan)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}


If we run the application, these will be the results:

Portrait orientation

Landscape orientation


We can see that the application in Landscape orientation doesn’t work perfectly but, using AnyLayout and with a few code tweaks, we will fix it easily.

[CONTENTVIEW.SWIFT]

import SwiftUI

struct ContentView: View {
    // with this variable we can handle the layout orientation
    @Environment(\.verticalSizeClass) var vSizeClass
    
    var body: some View {
        let layout = vSizeClass == .compact ? AnyLayout(HStackLayout()) : AnyLayout(VStackLayout())
        
        layout {
            Rectangle()
                .fill(.blue)
                .frame(width: 150, height: 150)
            Circle()
                .fill(.red)
                .frame(width: 150, height: 150)
            Capsule()
                .fill(.orange)
                .frame(width: 150, height: 100)
        }
        .padding()
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.cyan)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}



If we run the application, these will be the results:

Portrait orientation

Landscape orientation



Finally, we will now see how to switch the layout not with the device orientation but using a button.

[CONTENTVIEW.SWIFT]

import SwiftUI

struct ContentView: View {
    @State private var switchLayout = false
    
    var body: some View {
        let layout = switchLayout ? AnyLayout(HStackLayout()) : AnyLayout(VStackLayout())
        
        VStack{
            Button{
                self.switchLayout.toggle()
            }
            label:
            {
                Text("Change Layout")
                    .foregroundColor(Color.black)
            }
            
            layout {
                Rectangle()
                    .fill(.blue)
                    .frame(width: 150, height: 150)
                Circle()
                    .fill(.red)
                    .frame(width: 150, height: 150)
                Capsule()
                    .fill(.orange)
                    .frame(width: 150, height: 100)
            }
        }
        
        .animation(.default, value: self.switchLayout)
        .padding()
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.cyan)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}



If we run the application, these will be the results:

Portrait orientation

Landscape orientation



Leave a Reply

Your email address will not be published. Required fields are marked *