Skip to main content

How to automatically switch between HStack and VStack based on size class

About 3 minSwiftSwiftUIArticle(s)bloghackingwithswift.comcrashcourseswiftswiftuixcodeappstore

How to automatically switch between HStack and VStack based on size class 관련

SwiftUI by Example

Back to Home

How to automatically switch between HStack and VStack based on size class | SwiftUI by Example

How to automatically switch between HStack and VStack based on size class

Updated for Xcode 15

SwiftUI lets us monitor the current size class to decide how things should be laid out, for example switching from a HStack when space is plentiful to a VStack when space is restricted.

With a little thinking, we can write a new AdaptiveStack view that automatically switches between horizontal and vertical layouts for us. This makes creating great layouts on iPad simpler, because our layouts will automatically adjust to split view and slipover scenarios.

Here's how it looks:

struct AdaptiveStack<Content: View>: View {
    @Environment(\.horizontalSizeClass) var sizeClass
    let horizontalAlignment: HorizontalAlignment
    let verticalAlignment: VerticalAlignment
    let spacing: CGFloat?
    let content: () -> Content

    init(horizontalAlignment: HorizontalAlignment = .center, verticalAlignment: VerticalAlignment = .center, spacing: CGFloat? = nil, @ViewBuilder content: @escaping () -> Content) {
        self.horizontalAlignment = horizontalAlignment
        self.verticalAlignment = verticalAlignment
        self.spacing = spacing
        self.content = content
    }

    var body: some View {
        Group {
            if sizeClass == .compact {
                VStack(alignment: horizontalAlignment, spacing: spacing, content: content)
            } else {
                HStack(alignment: verticalAlignment, spacing: spacing, content: content)
            }
        }
    }
}

struct ContentView: View {
    var body: some View {
        AdaptiveStack {
            Text("Horizontal when there's lots of space")
            Text("but")
            Text("Vertical when space is restricted")
        }
    }
}

Download this as an Xcode projectopen in new window

An iPad showing two lines of text side-by-side in an app that spans the right two thirds of the screen. Another iPad showing two lines stacked vertically in an app that spans only the right third of the screen
An iPad showing two lines of text side-by-side in an app that spans the right two thirds of the screen. Another iPad showing two lines stacked vertically in an app that spans only the right third of the screen

To try it out, run the app in an iPad simulator, then try different sizes of split view – you'll see ContentView automatically switch to a VStack when space runs low.

Now to explain how the custom view works:

  • It monitors the horizontalSizeClass environment key, so that it will be updated every time that size class changes.
  • We've given it parameters to store horizontal and vertical alignment individually, so you can control exactly how your layout should adapt.
  • There's an optional CGFloat for spacing, because that's what VStack and HStack work with. If you wanted even more control you could add horizontalSpacing and verticalSpacing properties.
  • The content property is a function that accepts no parameters and returns some sort of content, which is the view builder end users will rely on to create their layouts.
  • Our initializer stashes them all away for later.
  • Inside the body property we can read the horizontal size class, then wrap a call to content() in either a VStack or HStack.

And that's it! The actual code isn't as hard you might imagine, but it gives us some really helpful flexibility.

Similar solutions…
How to dynamically change between VStack and HStack | SwiftUI by Example

How to dynamically change between VStack and HStack
How to create stacks using VStack and HStack | SwiftUI by Example

How to create stacks using VStack and HStack
How to dynamically adjust the appearance of a view based on its size and location | SwiftUI by Example

How to dynamically adjust the appearance of a view based on its size and location
How to create a document-based app using FileDocument and DocumentGroup | SwiftUI by Example

How to create a document-based app using FileDocument and DocumentGroup
How to create a toggle switch | SwiftUI by Example

How to create a toggle switch

이찬희 (MarkiiimarK)
Never Stop Learning.