banner
wangqiyang

wangqiyang

SwiftUI Introduction: Layout Basics

Basic Layout Containers#

Stack#

In SwiftUI, Stack is a fundamental view container used to arrange and layout other views. In a Stack, all child views are arranged in either a horizontal or vertical direction. You can use HStack to create a horizontal Stack, VStack to create a vertical Stack, or ZStack to create a Stack with a hierarchical relationship.

VStack#

In SwiftUI, VStack is a basic view container used to arrange other views vertically. VStack can contain any number of child views (there is actually a limit, but this can be circumvented using Group), and these child views will be arranged in order from top to bottom.

Here is a simple example of a VStack:

struct ContentView: View {
    var body: some View {
        VStack {
            Text("First")
            Text("Second")
            Text("Third")
        }
    }
}

In this example, the VStack contains three Text views, which are arranged in order from top to bottom.

In addition to basic layout, VStack also supports many other options and modifiers to help you customize the appearance and behavior of the views. Here are some commonly used options and modifiers:

  • alignment: Used to specify the alignment of child views in the vertical direction. By default, child views are aligned in the vertical center, but you can use the alignment option to specify other alignments, such as .leading, .trailing, .top, .bottom, etc.
  • spacing: Used to specify the spacing between child views. By default, there is no spacing between child views, but you can use the spacing option to add spacing, for example, VStack(spacing: 10) will add a spacing of 10 points between each child view.
  • padding: Used to specify the padding of the VStack. By default, the VStack has no padding, but you can use the padding option to add padding, for example, VStack().padding(10) will add 10 points of padding outside the VStack.

It is important to note that when you include multiple views in a VStack, their sizes and positions may be affected by other views. To avoid this, you can use a Spacer view to occupy extra space or use a GeometryReader to get the size of the parent view and adjust the child views as needed.

HStack#

Similar to VStack, the difference lies only in the direction. Here is a simple example of an HStack:

struct ContentView: View {
    var body: some View {
        HStack {
            Text("First")
            Text("Second")
            Text("Third")
        }
    }
}

In this example, the HStack contains three Text views, which are arranged in order from left to right.

The commonly used options and modifiers for HStack are similar to those for VStack:

  • alignment: Used to specify the alignment of child views in the horizontal direction. By default, child views are aligned in the horizontal center, but you can use the alignment option to specify other alignments, such as .leading, .trailing, .top, .bottom, etc.
  • spacing: Used to specify the spacing between child views. By default, there is no spacing between child views, but you can use the spacing option to add spacing, for example, HStack(spacing: 10) will add a spacing of 10 points between each child view.
  • padding: Used to specify the padding of the HStack. By default, the HStack has no padding, but you can use the padding option to add padding, for example, HStack().padding(10) will add 10 points of padding outside the HStack.

ZStack#

In SwiftUI, ZStack is a basic view container used to stack other views vertically. ZStack can contain any number of child views, which will be stacked in order from front to back, similar to layers. Here is a simple example of a ZStack:

struct ContentView: View {
    var body: some View {
        ZStack {
            Image("background")
            Text("Hello, World!")
        }
    }
}

In this example, the ZStack contains an Image view and a Text view, which are stacked together. Since the Text view is in front of the Image view, it will be displayed on top.

In addition to basic stacking, ZStack also supports many other options and modifiers to help you customize the appearance and behavior of the views. Here are some commonly used options and modifiers:

  • alignment: Used to specify the alignment of child views in the vertical direction. By default, child views are aligned in the vertical center, but you can use the alignment option to specify other alignments, such as .leading, .trailing, .top, .bottom, etc.
  • background: Used to specify the background view of the ZStack. By default, the ZStack has no background view, but you can use the background option to add a background view, for example, ZStack().background(Color.blue) will add a blue background behind the ZStack.
  • overlay: Used to add an overlay view on top of the ZStack. By default, the ZStack has no overlay view, but you can use the overlay option to add an overlay view, for example, ZStack().overlay(Text("Overlay")) will add an overlay view on top of the ZStack.

It is important to note that when you include multiple views in a ZStack, their sizes and positions may be affected by other views. To avoid this, you can use a Spacer view to occupy extra space or use a GeometryReader to get the size of the parent view and adjust the child views as needed.

LazyVStack#

LazyVStack is a view in SwiftUI used for vertical layout. LazyVStack is similar to VStack, but it has better performance and uses less memory because it only loads and displays its child views when needed. LazyVStack is typically used to display a large number of child views, such as lists and grids.

Here is the basic syntax for creating a LazyVStack:

LazyVStack(alignment: HorizontalAlignment = .center, spacing: CGFloat? = nil, pinnedViews: PinnedScrollableViews = .init(), @ViewBuilder content: () -> Content)

The alignment parameter is used to specify the alignment of child views along the vertical axis (e.g., .top, .center, .bottom, etc.), the spacing parameter is used to specify the spacing between child views, the pinnedViews parameter is used to specify views that should be pinned to the top or bottom of the ScrollView, and the content parameter is a closure that returns the content to be displayed in the LazyVStack.

For example, the following code creates a simple LazyVStack containing 10 text views:

LazyVStack {
    ForEach(1...10, id: \.self) { index in
        Text("Item \(index)")
    }
}

In this example, we use a ForEach loop to create 10 text views and add them to the LazyVStack. Since LazyVStack is "lazy," it will dynamically load and display each text view only when needed, which can improve performance and reduce memory usage.

LazyHStack#

LazyHStack is a view container in SwiftUI used to arrange a group of views horizontally. Unlike HStack, LazyHStack only instantiates its child views when needed, which can improve performance and reduce memory usage.

Here are some common uses of LazyHStack:

  1. Arranging a group of views: When you need to arrange a group of views horizontally, you can use LazyHStack to place them in a container. This makes it easier to layout views and perform lazy loading when needed, improving performance and memory efficiency.

For example, if you need to arrange a group of buttons in a view, you can use LazyHStack to place them in a horizontal container and perform lazy loading when needed.

LazyHStack {
    Button("Button 1") {
        // do something
    }
    Button("Button 2") {
        // do something
    }
    Button("Button 3") {
        // do something
    }
}
  1. Supporting layouts with a large number of views: When you need to place a large number of views in a single view, you can use LazyHStack for lazy loading, improving performance and memory efficiency. This is very useful for applications that need to display a large amount of data, such as social media apps, news apps, etc.

For example, if you need to display a group of images in a view, you can use LazyHStack to place them in a horizontal container and perform lazy loading when needed.

LazyHStack {
    ForEach(0..<100) { index in
        Image("image\(index)")
            .resizable()
            .frame(width: 50, height: 50)
    }
}

In summary, LazyHStack can help you layout and manage views more easily in SwiftUI, improving performance and memory efficiency. If you need to arrange a group of views horizontally and want to perform lazy loading when needed, then LazyHStack is a very practical view container.

Grid#

In SwiftUI, you can use LazyVGrid, LazyHGrid, and LazyGrid to create grid layouts. These containers provide a convenient way to arrange and layout many views, allowing you to easily create tables, photo walls, movie posters, and other complex layouts.

Here are some common methods and examples of using grid layouts in SwiftUI:

LazyVGrid#

Vertical grid layout: You can use the LazyVGrid container to create a grid layout in the vertical direction. In LazyVGrid, you can specify the number of columns, the spacing between rows, and the spacing between cells.

struct ContentView: View {
    let columns = [
        GridItem(.flexible()),
        GridItem(.flexible()),
        GridItem(.flexible())
    ]

    var body: some View {
        ScrollView {
            LazyVGrid(columns: columns, spacing: 16) {
                ForEach(0 ..< 10) { index in
                    Text("Item \(index)")
                        .frame(height: 100)
                }
            }
            .padding()
        }
    }
}

LazyHGrid#

Horizontal grid layout: You can use the LazyHGrid container to create a grid layout in the horizontal direction. In LazyHGrid, you can specify the number of rows, the spacing between columns, and the spacing between cells.

struct ContentView: View {
    let rows = [
        GridItem(.flexible()),
        GridItem(.flexible()),
        GridItem(.flexible())
    ]

    var body: some View {
        ScrollView(.horizontal) {
            LazyHGrid(rows: rows, spacing: 16) {
                ForEach(0 ..< 10) { index in
                    Text("Item \(index)")
                        .frame(width: 200, height: 100)
                }
            }
            .padding()
        }
    }
}

LazyGrid#

Custom grid layout: You can use the LazyGrid container to create a custom grid layout. In LazyGrid, you can specify the number of rows, the number of columns, the spacing between rows and columns, and customize the size and position of each cell.

struct ContentView: View {
    let columns = [
        GridItem(.flexible()),
        GridItem(.flexible()),
        GridItem(.flexible())
    ]

    var body: some View {
        ScrollView {
            LazyVGrid(columns: columns, spacing: 16) {
                ForEach(0 ..< 10) { index in
                    Text("Item \(index)")
                        .frame(height: CGFloat.random(in: 50...200))
                        .background(Color.blue)
                        .cornerRadius(8)
                        .overlay(
                            Text("\(index)")
                                .foregroundColor(.white)
                        )
                }
            }
            .padding()
        }
    }
}

ScrollView#

Basic Usage#

ScrollView is a view in SwiftUI used to display scrollable content. ScrollView can scroll vertically or horizontally and supports scroll gestures and scroll bars. ScrollView can be used to display various types of content, such as text, images, lists, etc.

Here is the basic syntax for creating a ScrollView:

struct ContentView: View {
    var body: some View {
        ScrollView {
            VStack {
                ForEach(0..<50) { index in
                    Text("Row \(index)")
                }
            }
        }
    }
}

In the ScrollView, we can add any number of views, including text views, image views, list views, etc. ScrollView will automatically wrap these views in a scrollable container and adjust their sizes and positions based on the content.

For example, the following code creates a simple ScrollView containing a text view:

ScrollView {
    Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed vel ante ac lorem bibendum semper. Nulla facilisi. Sed quis risus nec risus bibendum tempus. Nam luctus hendrerit eros, a tempor augue pharetra vel. Donec at risus vitae velit malesuada egestas.")
}

In this example, ScrollView will automatically wrap the text view in a scrollable container and adjust its size and position based on the length of the text. Users can scroll the text view using gestures or control the scroll position using the scroll bar.

Common Modifiers#

Here are some commonly used modifiers for ScrollView:

  1. scrollIndicatorInsets(_ :): Used to set the insets for the scroll indicator. This modifier accepts an EdgeInsets type parameter to specify the insets for the top, bottom, left, and right.
  2. showsIndicators(_ :): Used to control whether to show the scroll indicator. This modifier accepts a Boolean type parameter, with a default value of true, indicating that the scroll indicator is displayed. If set to false, the scroll indicator will not be displayed.
  3. onOffsetChange(_ :): Used to perform custom actions when the ScrollView is scrolled. This modifier accepts a closure type parameter that contains the current offset value. You can use this modifier to implement custom scrolling behavior, such as performing certain actions when scrolling to a specific position.
  4. contentInsets(_ :): Used to set the insets for the content of the ScrollView. This modifier accepts an EdgeInsets type parameter to specify the insets for the top, bottom, left, and right.
  5. contentOffset(_ :): Used to set the initial offset of the ScrollView. This modifier accepts a CGPoint type parameter to specify the initial offset of the ScrollView.
  6. background(_ :): Used to set the background of the ScrollView. This modifier accepts a View type parameter to specify the background view of the ScrollView.
  7. overlay(_ :): Used to add an overlay view on top of the ScrollView. This modifier accepts a View type parameter to specify the overlay view to be added to the ScrollView.
  8. ignoresSafeArea(_ edges: Edge.Set): Used to control whether the ScrollView ignores the safe area. This modifier accepts an Edge.Set type parameter to specify which edges of the safe area to ignore.
  9. content(_ :): Used to specify the content view of the ScrollView. This modifier accepts a View type parameter to specify the content view of the ScrollView.

Spacer#

Spacer is a view modifier in SwiftUI used to create a placeholder in a view to occupy space during layout. When you use Spacer, it automatically fills the remaining available space, pushing the views to the edges of the view container.

Here are some common uses of Spacer:

  1. Using Spacer in VStack or HStack: When you place a Spacer in a VStack or HStack, it will automatically push the views before it to the top or left of the container and push the views after it to the bottom or right of the container. This allows you to create adaptive layouts within the container.

For example, if you want to create a title with a fixed height and a text view with an adaptive height in a VStack, you can add a Spacer between them. This will cause the text view to automatically fill the remaining available space, pushing it to the bottom of the container.

VStack {
    Text("Title")
        .font(.largeTitle)
        .frame(height: 100)
    Spacer()
    Text("This is a long text that should wrap over several lines and fill the remaining space in the container.")
}
  1. Using Spacer in ZStack: When you place a Spacer in a ZStack, it will push the views before it to the front and the views after it to the back, automatically occupying the remaining available space. This allows you to create adaptive layouts in the ZStack.

For example, if you want to create a circular image with a fixed size and a rectangular view with an adaptive size in a ZStack, you can add a Spacer between them. This will cause the rectangular view to automatically fill the remaining available space, pushing it around the circular image.

ZStack {
    Circle()
        .fill(Color.blue)
        .frame(width: 100, height: 100)
    Spacer()
    Rectangle()
        .fill(Color.red)
        .frame(maxWidth: .infinity, maxHeight: .infinity)
}

In summary, Spacer can help you create adaptive layouts in SwiftUI, allowing views to automatically fill the remaining available space, resulting in more flexible and dynamic layout effects.

Group#

Group is a container view in SwiftUI used to group multiple views together. It does not create any new view hierarchy in the view hierarchy, but simply treats the views inside it as a group.

Here are some common uses of Group:

  1. Grouping multiple views together: When you need to group multiple views together, you can use Group to wrap them in a container. This allows for better organization of views in the code, making it easier to read and maintain.

For example, if you need to display multiple buttons in a view, you can place these buttons in a Group, allowing them to be treated as a whole and easily styled and laid out when needed.

Group {
    Button("Button 1") {
        // do something
    }
    Button("Button 2") {
        // do something
    }
    Button("Button 3") {
        // do something
    }
}
  1. Grouping views: When you need to group views, you can use Group to wrap them in a container. This makes it easy to organize similar views together and treat them as a whole.

For example, if you need to display multiple text labels in a view, you can group them in a Group and add styles and layout properties to that group. This can help better organize the code and make it easier to maintain.

Group {
    Text("Label 1")
    Text("Label 2")
    Text("Label 3")
}
.font(.largeTitle)
.padding()

In summary, Group can help you better organize and manage views in SwiftUI, making them easier to read and maintain. It is a very simple yet practical container view that can make the code cleaner and more readable.

Nested Layouts#

In SwiftUI, you can create complex layouts by nesting a view container. This allows you to use multiple containers, each responsible for managing a group of views. This makes it easier to combine and layout views and perform lazy loading when needed to improve performance and memory efficiency.

Here are some common examples of nested layouts in SwiftUI:

  1. Combining vertical and horizontal layouts: You can use a combination of VStack and HStack to achieve a mix of vertical and horizontal layouts. This is very useful for applications that need to arrange views in both horizontal and vertical directions, such as forms, toolbars, etc.
VStack {
    HStack {
        Text("First")
        Text("Second")
    }
    HStack {
        Text("Third")
        Text("Fourth")
    }
}
  1. Nested lists: You can nest list views within another list or view container to create more complex layouts. This is very useful for applications that need to display hierarchical data, such as directories, navigation, etc.
List {
    Section(header: Text("Section 1")) {
        Text("Item 1")
        Text("Item 2")
    }
    Section(header: Text("Section 2")) {
        List {
            Text("Nested Item 1")
            Text("Nested Item 2")
        }
    }
}
  1. Nested scroll views: You can nest scroll views within another scroll view or view container to create more complex scrolling layouts. This is very useful for applications that need to display a large amount of data, such as news, social media, etc.
ScrollView {
    VStack {
        Image("header-image")
            .resizable()
            .frame(height: 200)
        VStack {
            Text("Title")
                .font(.largeTitle)
            Text("Subtitle")
                .font(.headline)
                .foregroundColor(.gray)
            Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed euismod, ligula id gravida rutrum, sem urna volutpat purus, sit amet suscipit ex odio vel arcu. Nulla cursus sollicitudin massa. Etiam quis ex at odio eleifend mollis. Fusce accumsan turpis ac ipsum ultrices, nec lobortis dolor consectetur. Donec sit amet bibendum mi, id vestibulum justo. Sed eget dictum orci. Donec vitae quam ut eros rhoncus faucibus.")
                .font(.body)
        }
    }
}

Layout Modifiers#

In SwiftUI, layout modifiers can be used to add padding, backgrounds, overlay images, etc., around views. Here are some commonly used layout modifiers:

  1. padding(_:): Adds padding around the view. For example, Text("Hello World").padding() will add default padding around the Text view.
  2. background(_:): Adds a background to the view. For example, Text("Hello World").background(Color.blue) will add a blue background to the Text view.
  3. border(_:width:): Adds a border to the view. For example, Text("Hello World").border(Color.gray, width: 1) will add a gray border to the Text view with a width of 1.
  4. cornerRadius(_:): Adds rounded corners to the view. For example, Text("Hello World").cornerRadius(10) will add a corner radius of 10 points to the Text view.
  5. shadow(_:): Adds a shadow to the view. For example, Text("Hello World").shadow(color: .gray, radius: 2) will add a gray shadow to the Text view with a radius of 2.
  6. overlay(_:): Adds an overlay image on top of the view. For example, Text("Hello World").overlay(Image(systemName: "star")) will add a star image on top of the Text view.
  7. frame(width:height:alignment:): Specifies the frame size and alignment for the view. For example, Text("Hello World").frame(width: 100, height: 50, alignment: .center) will specify a frame for the Text view with a width of 100, height of 50, and centered alignment.
  8. aspectRatio(_:contentMode:): Specifies the aspect ratio and content mode for the view. For example, Image("photo").aspectRatio(1.5, contentMode: .fit) will specify an aspect ratio of 1.5 for the Image view and scale the image content to fit the view size.
  9. alignmentGuide(_:computeValue:): Allows you to define a custom alignment guide for use in layout. This modifier accepts two parameters: an alignment identifier and a computation function. For example, VStack(alignment: .leading) { ... }.alignmentGuide(.leading) { d in d[.trailing] } can set the position of the .leading alignment guide to the .trailing of its child views.
  10. fixedSize(): Specifies the size of the view to be equal to its content size. For example, Text("Hello World").fixedSize() will specify a size for the Text view equal to the size of its content.
  11. layoutPriority(_:): Specifies the layout priority of the view. Layout priority is used to determine which view will be prioritized in layout. For example, VStack { Text("Hello").layoutPriority(1); Text("World").layoutPriority(2) } will ensure that the Text("World") view has a higher layout priority and will be prioritized in layout.
  12. offset(_:): Adds an offset to the position of the view. For example, Text("Hello World").offset(x: 10, y: 20) will add an x-axis offset of 10 and a y-axis offset of 20 to the Text view.
  13. rotationEffect(_:anchor:): Adds a rotation effect to the view. For example, Text("Hello World").rotationEffect(.degrees(45)) will add a 45-degree rotation effect to the Text view.
  14. scaleEffect(_:anchor:): Adds a scaling effect to the view. For example, Text("Hello World").scaleEffect(2) will double the size of the Text view.
  15. clipped(): Clips the view to the bounds of its parent view. For example, Image("photo").clipped() will clip the image to the bounds of its parent view.

Layout Priority#

In SwiftUI, layout priority is used to determine the relative position of views in a layout. Views with higher layout priority will be considered first during layout and will be allocated available space preferentially. If all views have the same layout priority, they will share the available space equally.

You can use the layoutPriority(_:) modifier to set the layout priority for a view. This modifier accepts a floating-point value as a parameter, representing the layout priority of the view. By default, all views have a layout priority of 0.

For example, you can use the following code to set layout priorities for two text views:

VStack {
    Text("First").layoutPriority(1)
    Text("Second").layoutPriority(2)
}

In the code above, the second text view has a higher layout priority, so it will be allocated available space first. If it needs more space, it will be prioritized and allocated as much available space as possible. The first text view, having a lower layout priority, will be allocated as little available space as possible.

It is important to note that layout priority can only be used to determine the relative position of child views within a parent view, and cannot be used to determine the absolute position of child views on the screen. If you want more precise layout control, you can consider using other layout modifiers such as frame, padding, offset, etc.

Automatic Layout#

In SwiftUI, automatic layout is achieved using a method called "declarative layout." This method allows you to control the layout of views by declaring the expected behavior of the views, rather than directly manipulating the layout. This method is very similar to creating web pages using HTML and CSS.

Automatic layout in SwiftUI is based on a set of built-in layout systems, including VStack, HStack, ZStack, List, ScrollView, etc. These layout systems can be nested and customized by adding modifiers.

For example, the following code uses VStack and HStack to create a simple layout:

VStack {
    HStack {
        Text("Hello")
        Text("World")
    }
    Text("How are you?")
}

In the code above, VStack and HStack represent vertical and horizontal layouts, respectively, allowing them to be nested to create more complex layouts. In this example, the HStack contains two text views, which are arranged side by side in the horizontal direction. The VStack contains an HStack and a text view, which are arranged in the vertical direction. Thus, the entire layout contains three text views, with two arranged side by side in the horizontal direction and the third arranged in the vertical direction.

It is important to note that automatic layout in SwiftUI is responsive, meaning that views will automatically adjust their sizes and positions based on their content and environment. For example, when the device's screen orientation changes, the layout of the views will automatically update to accommodate the new orientation.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.