“This is the fifth day of my participation in the First Challenge 2022. For details: First Challenge 2022”

Use Size Class to create different layouts

SwiftUI uses Size Class to create different layouts. To use them, first create an @Environment object that will store its value, then examine the value of that property as needed, looking for.compact or.regular size classes.

struct ContentView: View {
    @Environment(.horizontalSizeClass) var horizontalSizeClass

    var body: some View {
        if horizontalSizeClass = = .compact {
            Text("Compact")}else {
            Text("Regular")}}}Copy the code

Size Class is a great way to make your user interface intelligently fit the available space by using VStack or HStack for your content. For example, if you have a lot of space, you might place things horizontally, but switch to a vertical layout when space is limited.

Use Size Class to automatically switch between Vstack and HStack

SwiftUI can monitor the current size class to determine how it should be arranged, such as switching from HStack when there is plenty of space to VStack when space is limited.

A new AdaptiveStack view can be written that will automatically switch between horizontal and vertical layouts for us. This makes it much easier to create great layouts on the iPad,

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")}}}Copy the code

  • First, listen on the HorizontalSizeClass in the custom View so that it will be updated every time the size class changes.

  • And it provides separate storage of horizontal and vertical alignment parameters, so you can control exactly how the layout should fit.

  • There is an optional CGFloat value for spacing, because that’s how VStack and HStack work. If you want more control, you can add the HorizontalSpacing and verticalSpacing attributes.

  • The Content property is a function that takes no arguments and returns something that will eventually be relied on to create their layout.

  • Our initializer hides them all for later use.

  • In the Body property, you can read the horizontal dimension class and wrap the call to Content () in either VStack or HStack.

Use ScrollView

SwiftUI’s ScrollView allows developers to create a scrolling container for views with relative ease, as it automatically resists itself to fit what we put in it, and also automatically adds additional illustrations to avoid safe areas.

ScrollView {
    VStack(spacing: 20) {
        ForEach(0..<10) {
            Text("Item ($0)")
                .foregroundColor(.white)
                .font(.largeTitle)
                .frame(width: 200, height: 200)
                .background(Color.red)
        }
    }
}
.frame(height: 350)
Copy the code

By default, the scroll view is vertical, but you can control the axis by passing.horizontal as the first argument. Therefore, we can flip the previous example horizontally, as follows:

ScrollView(.horizontal) {
    HStack(spacing: 20) {
        ForEach(0..<10) {
            Text("Item ($0)")
                .foregroundColor(.white)
                .font(.largeTitle)
                .frame(width: 200, height: 200)
                .background(Color.red)
        }
    }
}
Copy the code

You can specify two shafts simultaneously using the [. Horizontal,. Vertical].

ScrollView(.horizontal, showsIndicators: false) {
    HStack(spacing: 20) {
        ForEach(0..<10) {
            Text("Item ($0)")
                .foregroundColor(.white)
                .font(.largeTitle)
                .frame(width: 200, height: 200)
                .background(Color.red)
        }
    }
}
Copy the code

Slide the ScrollView to the specified position

If you want to programmatically move SwiftUI’s ScrollView to a specific location, you should embed a ScrollViewReader in it. This provides a scrollTo() method that can move to any view within the parent scroll view by providing its anchor point.

For example, this creates 100 colored boxes in the vertical scroll view, and when you press the button, it scrolls directly to the box with ID 8:

struct ContentView: View {
    let colors: [Color] = [.red, .green, .blue]

    var body: some View {
        ScrollView {
            ScrollViewReader { value in
                Button("Jump to #8") {
                    value.scrollTo(8)
                }
                .padding()

                ForEach(0..<100) { i in
                    Text("Example (i)")
                        .font(.title)
                        .frame(width: 200, height: 200)
                        .background(colors[i % colors.count])
                        .id(i)
                }
            }
        }
        .frame(height: 350)}}Copy the code

For better control of scrolling, you can specify a second parameter called an anchor point to control the position of the target view after scrolling is complete.

For example, this will scroll to the same view as before, but this time put that view at the top:

struct ContentView: View {
    let colors: [Color] = [.red, .green, .blue]

    var body: some View {
        ScrollView {
            ScrollViewReader { value in
                Button("Jump to #8") {
                    value.scrollTo(8, anchor: .top)
                }
                .padding()

                ForEach(0..<100) { i in
                    Text("Example (i)")
                        .font(.title)
                        .frame(width: 200, height: 200)
                        .background(colors[i % colors.count])
                        .id(i)
                }
            }
        }
        .frame(height: 350)}}Copy the code