SwiftUI布局完全指南:从入门到精通

从基础到高级,涵盖各种View组件的使用。

SwiftUI 布局完全指南

项目结构

复制代码
SwiftUILayoutTutorial/
├── App/
│   └── LayoutTutorialApp.swift
├── Views/
│   ├── ContentView.swift
│   ├── BasicViews/
│   │   ├── TextViews.swift
│   │   ├── ImageViews.swift
│   │   ├── ButtonViews.swift
│   │   └── InputViews.swift
│   ├── LayoutViews/
│   │   ├── StackLayouts.swift
│   │   ├── GridLayouts.swift
│   │   ├── ScrollViews.swift
│   │   └── ContainerViews.swift
│   ├── AdvancedViews/
│   │   ├── NavigationViews.swift
│   │   ├── TabViews.swift
│   │   ├── SheetAndAlert.swift
│   │   └── GestureViews.swift
│   └── Components/
│       ├── CustomModifiers.swift
│       ├── Animations.swift
│       └── Transitions.swift
  1. 主应用文件 (App/LayoutTutorialApp.swift)
swift 复制代码
import SwiftUI

@main
struct LayoutTutorialApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}
  1. 主内容视图 (Views/ContentView.swift)
swift 复制代码
import SwiftUI

struct ContentView: View {
    @State private var selectedTab = 0
    
    var body: some View {
        NavigationView {
            List {
                Section("基础视图组件") {
                    NavigationLink("文本视图 (Text)") { TextViews() }
                    NavigationLink("图片视图 (Image)") { ImageViews() }
                    NavigationLink("按钮视图 (Button)") { ButtonViews() }
                    NavigationLink("输入视图 (Input)") { InputViews() }
                }
                
                Section("布局容器") {
                    NavigationLink("堆栈布局 (HStack/VStack/ZStack)") { StackLayouts() }
                    NavigationLink("网格布局 (Grid)") { GridLayouts() }
                    NavigationLink("滚动视图 (ScrollView)") { ScrollViews() }
                    NavigationLink("容器视图 (Container)") { ContainerViews() }
                }
                
                Section("高级功能") {
                    NavigationLink("导航视图 (Navigation)") { NavigationViews() }
                    NavigationLink("标签视图 (TabView)") { TabViews() }
                    NavigationLink("弹窗和警告 (Sheet & Alert)") { SheetAndAlert() }
                    NavigationLink("手势识别 (Gesture)") { GestureViews() }
                }
                
                Section("动画与效果") {
                    NavigationLink("基础动画 (Animation)") { BasicAnimations() }
                    NavigationLink("转场效果 (Transition)") { TransitionViews() }
                    NavigationLink("自定义修饰符 (Modifier)") { CustomModifierViews() }
                }
            }
            .navigationTitle("SwiftUI 布局教程")
            .listStyle(InsetGroupedListStyle())
        }
    }
}
  1. 基础视图组件

3.1 文本视图 (Views/BasicViews/TextViews.swift)

swift 复制代码
import SwiftUI

struct TextViews: View {
    var body: some View {
        ScrollView {
            VStack(spacing: 30) {
                // 基础文本
                GroupBox("基础文本") {
                    VStack(spacing: 15) {
                        Text("普通文本")
                        Text("自定义字体大小")
                            .font(.title)
                        Text("加粗文本")
                            .fontWeight(.bold)
                        Text("斜体文本")
                            .italic()
                        Text("下划线文本")
                            .underline()
                        Text("删除线文本")
                            .strikethrough()
                    }
                    .frame(maxWidth: .infinity)
                    .padding()
                }
                
                // 文本颜色和背景
                GroupBox("颜色和背景") {
                    VStack(spacing: 15) {
                        Text("红色文本")
                            .foregroundColor(.red)
                        Text("蓝色背景")
                            .background(Color.blue)
                            .foregroundColor(.white)
                        Text("圆角背景")
                            .padding()
                            .background(Color.green)
                            .cornerRadius(10)
                        Text("带边框的文本")
                            .padding()
                            .overlay(
                                RoundedRectangle(cornerRadius: 10)
                                    .stroke(Color.blue, lineWidth: 2)
                            )
                    }
                    .frame(maxWidth: .infinity)
                    .padding()
                }
                
                // 文本样式
                GroupBox("文本样式") {
                    VStack(spacing: 15) {
                        Text("多行文本会自动换行显示,当文本内容超过一行时,SwiftUI会自动处理换行")
                            .lineLimit(2)
                        
                        Text("固定宽度的文本,超出部分会被截断...")
                            .frame(width: 200)
                            .truncationMode(.tail)
                        
                        Text("自定义行间距")
                            .lineSpacing(10)
                        
                        Text("字符间距")
                            .kerning(2)
                        
                        Text("等宽字体")
                            .font(.system(.body, design: .monospaced))
                    }
                    .frame(maxWidth: .infinity)
                    .padding()
                }
                
                // 富文本
                GroupBox("富文本") {
                    VStack(spacing: 15) {
                        Text("普通文本 + ") + Text("高亮文本")
                            .bold()
                            .foregroundColor(.blue) + Text(" + 普通文本")
                        
                        Text("\(Image(systemName: "star.fill")) 带图标的文本")
                    }
                    .frame(maxWidth: .infinity)
                    .padding()
                }
                
                // 文本对齐
                GroupBox("文本对齐") {
                    VStack(spacing: 15) {
                        Text("左对齐")
                            .frame(maxWidth: .infinity, alignment: .leading)
                            .background(Color.gray.opacity(0.2))
                        
                        Text("居中对齐")
                            .frame(maxWidth: .infinity, alignment: .center)
                            .background(Color.gray.opacity(0.2))
                        
                        Text("右对齐")
                            .frame(maxWidth: .infinity, alignment: .trailing)
                            .background(Color.gray.opacity(0.2))
                    }
                    .frame(maxWidth: .infinity)
                    .padding()
                }
            }
            .padding()
        }
        .navigationTitle("文本视图")
    }
}

3.2 图片视图 (Views/BasicViews/ImageViews.swift)

swift 复制代码
import SwiftUI

struct ImageViews: View {
    var body: some View {
        ScrollView {
            VStack(spacing: 30) {
                // 系统图标
                GroupBox("SF Symbols 图标") {
                    HStack(spacing: 20) {
                        Image(systemName: "heart.fill")
                            .foregroundColor(.red)
                            .font(.largeTitle)
                        
                        Image(systemName: "star.fill")
                            .foregroundColor(.yellow)
                            .font(.largeTitle)
                        
                        Image(systemName: "person.circle.fill")
                            .foregroundColor(.blue)
                            .font(.largeTitle)
                        
                        Image(systemName: "bell.fill")
                            .foregroundColor(.orange)
                            .font(.largeTitle)
                    }
                    .frame(maxWidth: .infinity)
                    .padding()
                }
                
                // 图片大小调整
                GroupBox("图片大小调整") {
                    VStack(spacing: 15) {
                        Image(systemName: "photo")
                            .resizable()
                            .frame(width: 100, height: 100)
                            .foregroundColor(.blue)
                        
                        Text("自适应比例")
                            .font(.caption)
                        Image(systemName: "photo")
                            .resizable()
                            .aspectRatio(contentMode: .fit)
                            .frame(height: 100)
                            .foregroundColor(.green)
                    }
                    .frame(maxWidth: .infinity)
                    .padding()
                }
                
                // 图片样式
                GroupBox("图片样式") {
                    VStack(spacing: 15) {
                        HStack(spacing: 20) {
                            Image(systemName: "photo")
                                .resizable()
                                .frame(width: 80, height: 80)
                                .clipShape(Circle())
                            
                            Image(systemName: "photo")
                                .resizable()
                                .frame(width: 80, height: 80)
                                .clipShape(RoundedRectangle(cornerRadius: 15))
                            
                            Image(systemName: "photo")
                                .resizable()
                                .frame(width: 80, height: 80)
                                .clipShape(Ellipse())
                        }
                        
                        HStack(spacing: 20) {
                            Image(systemName: "photo")
                                .resizable()
                                .frame(width: 80, height: 80)
                                .cornerRadius(10)
                                .overlay(
                                    RoundedRectangle(cornerRadius: 10)
                                        .stroke(Color.blue, lineWidth: 2)
                                )
                            
                            Image(systemName: "photo")
                                .resizable()
                                .frame(width: 80, height: 80)
                                .shadow(radius: 5)
                        }
                    }
                    .frame(maxWidth: .infinity)
                    .padding()
                }
                
                // 图片效果
                GroupBox("图片效果") {
                    VStack(spacing: 15) {
                        HStack(spacing: 20) {
                            Image(systemName: "photo")
                                .resizable()
                                .frame(width: 60, height: 60)
                                .opacity(0.5)
                            
                            Image(systemName: "photo")
                                .resizable()
                                .frame(width: 60, height: 60)
                                .blur(radius: 2)
                            
                            Image(systemName: "photo")
                                .resizable()
                                .frame(width: 60, height: 60)
                                .brightness(0.2)
                        }
                        
                        HStack(spacing: 20) {
                            Image(systemName: "photo")
                                .resizable()
                                .frame(width: 60, height: 60)
                                .contrast(0.5)
                            
                            Image(systemName: "photo")
                                .resizable()
                                .frame(width: 60, height: 60)
                                .saturation(0)
                            
                            Image(systemName: "photo")
                                .resizable()
                                .frame(width: 60, height: 60)
                                .colorInvert()
                        }
                    }
                    .frame(maxWidth: .infinity)
                    .padding()
                }
            }
            .padding()
        }
        .navigationTitle("图片视图")
    }
}

3.3 按钮视图 (Views/BasicViews/ButtonViews.swift)

swift 复制代码
import SwiftUI

struct ButtonViews: View {
    @State private var buttonCount = 0
    @State private var isPressed = false
    
    var body: some View {
        ScrollView {
            VStack(spacing: 30) {
                // 基础按钮
                GroupBox("基础按钮") {
                    VStack(spacing: 15) {
                        Button("普通按钮") {
                            print("按钮被点击")
                        }
                        
                        Button(action: {
                            buttonCount += 1
                        }) {
                            Text("计数按钮 (点击次数: \(buttonCount))")
                                .padding()
                                .background(Color.blue)
                                .foregroundColor(.white)
                                .cornerRadius(10)
                        }
                        
                        Button(action: {}) {
                            Label("带图标的按钮", systemImage: "star.fill")
                                .padding()
                                .background(Color.green)
                                .foregroundColor(.white)
                                .cornerRadius(10)
                        }
                    }
                    .frame(maxWidth: .infinity)
                    .padding()
                }
                
                // 按钮样式
                GroupBox("按钮样式") {
                    VStack(spacing: 15) {
                        Button("边框按钮") {}
                            .buttonStyle(BorderedButtonStyle())
                        
                        Button("边框突出按钮") {}
                            .buttonStyle(BorderedProminentButtonStyle())
                        
                        Button("普通边框") {}
                            .buttonStyle(.bordered)
                        
                        Button("突出边框") {}
                            .buttonStyle(.borderedProminent)
                    }
                    .frame(maxWidth: .infinity)
                    .padding()
                }
                
                // 自定义按钮
                GroupBox("自定义按钮") {
                    VStack(spacing: 15) {
                        // 渐变按钮
                        Button("渐变按钮") {}
                            .padding(.horizontal, 30)
                            .padding(.vertical, 12)
                            .background(
                                LinearGradient(
                                    gradient: Gradient(colors: [.blue, .purple]),
                                    startPoint: .leading,
                                    endPoint: .trailing
                                )
                            )
                            .foregroundColor(.white)
                            .cornerRadius(8)
                        
                        // 阴影按钮
                        Button("带阴影的按钮") {}
                            .padding(.horizontal, 30)
                            .padding(.vertical, 12)
                            .background(Color.orange)
                            .foregroundColor(.white)
                            .cornerRadius(8)
                            .shadow(color: .orange.opacity(0.5), radius: 5, x: 0, y: 2)
                        
                        // 圆形按钮
                        Button(action: {}) {
                            Image(systemName: "plus")
                                .font(.title)
                                .padding()
                                .background(Color.blue)
                                .foregroundColor(.white)
                                .clipShape(Circle())
                        }
                    }
                    .frame(maxWidth: .infinity)
                    .padding()
                }
                
                // 按压效果按钮
                GroupBox("按压效果") {
                    VStack(spacing: 15) {
                        Button("按压缩放效果") {
                            // 动作
                        }
                        .scaleEffect(isPressed ? 0.95 : 1.0)
                        .animation(.spring(), value: isPressed)
                        .onLongPressGesture(minimumDuration: 0) { pressing in
                            isPressed = pressing
                        } perform: {}
                        
                        Button("涟漪效果") {}
                            .padding()
                            .background(Color.purple)
                            .foregroundColor(.white)
                            .cornerRadius(8)
                            .simultaneousGesture(
                                TapGesture()
                                    .onEnded { _ in
                                        // 添加涟漪效果
                                    }
                            )
                    }
                    .frame(maxWidth: .infinity)
                    .padding()
                }
            }
            .padding()
        }
        .navigationTitle("按钮视图")
    }
}

3.4 输入视图 (Views/BasicViews/InputViews.swift)

swift 复制代码
import SwiftUI

struct InputViews: View {
    @State private var text = ""
    @State private var secureText = ""
    @State private var multiLineText = ""
    @State private var sliderValue = 50.0
    @State private var stepperValue = 0
    @State private var toggleValue = false
    @State private var pickerSelection = "选项1"
    @State private var date = Date()
    @State private var color = Color.blue
    
    let pickerOptions = ["选项1", "选项2", "选项3"]
    
    var body: some View {
        ScrollView {
            VStack(spacing: 25) {
                // 文本输入
                GroupBox("文本输入") {
                    VStack(spacing: 15) {
                        TextField("普通文本输入", text: $text)
                            .textFieldStyle(RoundedBorderTextFieldStyle())
                        
                        SecureField("密码输入", text: $secureText)
                            .textFieldStyle(RoundedBorderTextFieldStyle())
                        
                        TextEditor(text: $multiLineText)
                            .frame(height: 100)
                            .overlay(
                                RoundedRectangle(cornerRadius: 8)
                                    .stroke(Color.gray.opacity(0.3), lineWidth: 1)
                            )
                            .cornerRadius(8)
                        
                        if !text.isEmpty {
                            Text("输入的内容: \(text)")
                                .font(.caption)
                        }
                    }
                    .padding(.vertical, 8)
                }
                
                // 滑块和步进器
                GroupBox("滑块和步进器") {
                    VStack(spacing: 15) {
                        HStack {
                            Text("滑块值: \(Int(sliderValue))")
                            Slider(value: $sliderValue, in: 0...100, step: 1)
                        }
                        
                        HStack {
                            Text("步进值: \(stepperValue)")
                            Stepper("调整数值", value: $stepperValue, in: 0...10)
                        }
                    }
                    .padding(.vertical, 8)
                }
                
                // 开关和选择器
                GroupBox("开关和选择器") {
                    VStack(spacing: 15) {
                        Toggle("开关按钮", isOn: $toggleValue)
                        
                        if toggleValue {
                            Text("开关已打开")
                                .foregroundColor(.green)
                        }
                        
                        Picker("选择器", selection: $pickerSelection) {
                            ForEach(pickerOptions, id: \.self) { option in
                                Text(option).tag(option)
                            }
                        }
                        .pickerStyle(SegmentedPickerStyle())
                    }
                    .padding(.vertical, 8)
                }
                
                // 日期选择器
                GroupBox("日期选择器") {
                    VStack(spacing: 15) {
                        DatePicker("选择日期", selection: $date, displayedComponents: .date)
                        DatePicker("选择时间", selection: $date, displayedComponents: .hourAndMinute)
                        DatePicker("完整日期时间", selection: $date)
                            .datePickerStyle(CompactDatePickerStyle())
                    }
                    .padding(.vertical, 8)
                }
                
                // 颜色选择器
                GroupBox("颜色选择器") {
                    ColorPicker("选择颜色", selection: $color)
                        .padding(.vertical, 8)
                    
                    RoundedRectangle(cornerRadius: 10)
                        .fill(color)
                        .frame(height: 50)
                }
                
                // 表单输入组合
                GroupBox("表单示例") {
                    VStack(spacing: 15) {
                        HStack {
                            Text("姓名:")
                                .frame(width: 60, alignment: .leading)
                            TextField("请输入姓名", text: $text)
                                .textFieldStyle(RoundedBorderTextFieldStyle())
                        }
                        
                        HStack {
                            Text("年龄:")
                                .frame(width: 60, alignment: .leading)
                            Stepper("\(stepperValue)岁", value: $stepperValue, in: 0...120)
                        }
                        
                        HStack {
                            Text("性别:")
                                .frame(width: 60, alignment: .leading)
                            Picker("", selection: $pickerSelection) {
                                Text("男").tag("男")
                                Text("女").tag("女")
                            }
                            .pickerStyle(SegmentedPickerStyle())
                        }
                    }
                    .padding(.vertical, 8)
                }
            }
            .padding()
        }
        .navigationTitle("输入视图")
    }
}
  1. 布局容器

4.1 堆栈布局 (Views/LayoutViews/StackLayouts.swift)

swift 复制代码
import SwiftUI

struct StackLayouts: View {
    var body: some View {
        ScrollView {
            VStack(spacing: 30) {
                // HStack 水平布局
                GroupBox("HStack - 水平布局") {
                    HStack(spacing: 20) {
                        ColorBlock(color: .red, text: "1")
                        ColorBlock(color: .green, text: "2")
                        ColorBlock(color: .blue, text: "3")
                    }
                    .frame(maxWidth: .infinity)
                    .padding()
                    
                    Text("对齐方式")
                        .font(.caption)
                    
                    HStack(alignment: .top, spacing: 20) {
                        ColorBlock(color: .orange, text: "顶部对齐", height: 80)
                        ColorBlock(color: .orange, text: "顶部对齐", height: 60)
                        ColorBlock(color: .orange, text: "顶部对齐", height: 100)
                    }
                    .frame(maxWidth: .infinity)
                    .padding()
                    .background(Color.gray.opacity(0.1))
                }
                
                // VStack 垂直布局
                GroupBox("VStack - 垂直布局") {
                    VStack(spacing: 10) {
                        ColorBlock(color: .purple, text: "1")
                        ColorBlock(color: .purple, text: "2")
                        ColorBlock(color: .purple, text: "3")
                    }
                    .frame(maxWidth: .infinity)
                    .padding()
                    
                    Text("对齐方式")
                        .font(.caption)
                    
                    VStack(alignment: .leading, spacing: 10) {
                        Text("左对齐文本")
                        Text("这也是左对齐")
                        Text("更长的文本也是左对齐")
                    }
                    .frame(maxWidth: .infinity, alignment: .leading)
                    .padding()
                    .background(Color.gray.opacity(0.1))
                }
                
                // ZStack 层叠布局
                GroupBox("ZStack - 层叠布局") {
                    ZStack {
                        ColorBlock(color: .blue.opacity(0.6), text: "底层")
                        ColorBlock(color: .green.opacity(0.6), text: "中间层")
                        ColorBlock(color: .yellow.opacity(0.6), text: "顶层")
                    }
                    .frame(height: 150)
                    .padding()
                    
                    Text("层叠对齐示例")
                        .font(.caption)
                    
                    ZStack(alignment: .bottomTrailing) {
                        RoundedRectangle(cornerRadius: 10)
                            .fill(Color.gray.opacity(0.2))
                            .frame(height: 150)
                        
                        Text("右下角")
                            .padding()
                            .background(Color.blue)
                            .foregroundColor(.white)
                            .cornerRadius(5)
                            .padding()
                    }
                    .frame(maxWidth: .infinity)
                    .padding()
                }
                
                // 组合布局
                GroupBox("组合布局示例") {
                    VStack(spacing: 15) {
                        HStack {
                            Image(systemName: "person.circle.fill")
                                .font(.largeTitle)
                            VStack(alignment: .leading) {
                                Text("张三")
                                    .font(.headline)
                                Text("iOS开发者")
                                    .font(.caption)
                                    .foregroundColor(.gray)
                            }
                            Spacer()
                            Button("关注") {}
                                .buttonStyle(BorderedButtonStyle())
                        }
                        
                        Divider()
                        
                        HStack(spacing: 20) {
                            VStack {
                                Text("100")
                                    .font(.title2)
                                    .bold()
                                Text("文章")
                                    .font(.caption)
                            }
                            VStack {
                                Text("1000")
                                    .font(.title2)
                                    .bold()
                                Text("粉丝")
                                    .font(.caption)
                            }
                            VStack {
                                Text("500")
                                    .font(.title2)
                                    .bold()
                                Text("点赞")
                                    .font(.caption)
                            }
                        }
                        .frame(maxWidth: .infinity)
                    }
                    .padding()
                    .background(Color.gray.opacity(0.1))
                    .cornerRadius(10)
                }
            }
            .padding()
        }
        .navigationTitle("堆栈布局")
    }
}

// 辅助组件
struct ColorBlock: View {
    let color: Color
    let text: String
    var height: CGFloat = 50
    
    var body: some View {
        RoundedRectangle(cornerRadius: 8)
            .fill(color)
            .frame(height: height)
            .overlay(
                Text(text)
                    .foregroundColor(.white)
                    .bold()
            )
    }
}

4.2 网格布局 (Views/LayoutViews/GridLayouts.swift)

swift 复制代码
import SwiftUI

struct GridLayouts: View {
    let columns = [
        GridItem(.flexible()),
        GridItem(.flexible()),
        GridItem(.flexible())
    ]
    
    let adaptiveColumns = [
        GridItem(.adaptive(minimum: 80))
    ]
    
    let fixedColumns = [
        GridItem(.fixed(100)),
        GridItem(.fixed(100)),
        GridItem(.fixed(100))
    ]
    
    var body: some View {
        ScrollView {
            VStack(spacing: 30) {
                // LazyVGrid 基础用法
                GroupBox("LazyVGrid - 灵活网格") {
                    LazyVGrid(columns: columns, spacing: 15) {
                        ForEach(1...9, id: \.self) { index in
                            GridItemView(number: index, color: .blue)
                        }
                    }
                    .padding()
                }
                
                // 自适应网格
                GroupBox("自适应网格") {
                    LazyVGrid(columns: adaptiveColumns, spacing: 15) {
                        ForEach(1...10, id: \.self) { index in
                            GridItemView(number: index, color: .green)
                        }
                    }
                    .padding()
                }
                
                // 固定宽度网格
                GroupBox("固定宽度网格") {
                    LazyVGrid(columns: fixedColumns, spacing: 15) {
                        ForEach(1...6, id: \.self) { index in
                            GridItemView(number: index, color: .orange)
                        }
                    }
                    .padding()
                }
                
                // 不同大小的网格项
                GroupBox("不同大小的网格项") {
                    let mixedColumns = [
                        GridItem(.flexible()),
                        GridItem(.flexible()),
                        GridItem(.flexible())
                    ]
                    
                    LazyVGrid(columns: mixedColumns, spacing: 15) {
                        GridItemView(number: 1, color: .purple)
                            .frame(height: 100)
                        GridItemView(number: 2, color: .purple)
                            .frame(height: 60)
                        GridItemView(number: 3, color: .purple)
                            .frame(height: 80)
                        GridItemView(number: 4, color: .purple)
                            .frame(height: 120)
                        GridItemView(number: 5, color: .purple)
                            .frame(height: 70)
                        GridItemView(number: 6, color: .purple)
                            .frame(height: 90)
                    }
                    .padding()
                }
                
                // LazyHGrid 水平网格
                GroupBox("LazyHGrid - 水平网格") {
                    ScrollView(.horizontal) {
                        LazyHGrid(rows: [GridItem(.fixed(100))], spacing: 15) {
                            ForEach(1...15, id: \.self) { index in
                                GridItemView(number: index, color: .red)
                                    .frame(width: 100)
                            }
                        }
                        .padding()
                    }
                }
                
                // 实际应用示例 - 图片画廊
                GroupBox("实际应用:图片画廊") {
                    LazyVGrid(columns: columns, spacing: 15) {
                        ForEach(1...6, id: \.self) { index in
                            VStack {
                                RoundedRectangle(cornerRadius: 10)
                                    .fill(Color.blue.opacity(0.3))
                                    .frame(height: 100)
                                    .overlay(
                                        Image(systemName: "photo")
                                            .font(.largeTitle)
                                            .foregroundColor(.blue)
                                    )
                                
                                Text("图片 \(index)")
                                    .font(.caption)
                            }
                        }
                    }
                    .padding()
                }
            }
            .padding()
        }
        .navigationTitle("网格布局")
    }
}

struct GridItemView: View {
    let number: Int
    let color: Color
    
    var body: some View {
        RoundedRectangle(cornerRadius: 10)
            .fill(color.opacity(0.2))
            .frame(height: 80)
            .overlay(
                VStack {
                    Text("\(number)")
                        .font(.title2)
                        .bold()
                        .foregroundColor(color)
                    Text("项目")
                        .font(.caption)
                        .foregroundColor(color)
                }
            )
            .overlay(
                RoundedRectangle(cornerRadius: 10)
                    .stroke(color, lineWidth: 1)
            )
    }
}

4.3 滚动视图 (Views/LayoutViews/ScrollViews.swift)

swift 复制代码
import SwiftUI

struct ScrollViews: View {
    @State private var scrollOffset: CGFloat = 0
    
    var body: some View {
        VStack {
            // 垂直滚动
            GroupBox("垂直滚动") {
                ScrollView {
                    VStack(spacing: 10) {
                        ForEach(1...20, id: \.self) { index in
                            HStack {
                                Text("项目 \(index)")
                                Spacer()
                                Image(systemName: "chevron.right")
                                    .foregroundColor(.gray)
                            }
                            .padding()
                            .background(Color.gray.opacity(0.1))
                            .cornerRadius(8)
                        }
                    }
                    .padding()
                }
                .frame(height: 300)
            }
            
            // 水平滚动
            GroupBox("水平滚动") {
                ScrollView(.horizontal, showsIndicators: false) {
                    HStack(spacing: 15) {
                        ForEach(1...15, id: \.self) { index in
                            RoundedRectangle(cornerRadius: 10)
                                .fill(Color.blue.opacity(0.2))
                                .frame(width: 150, height: 120)
                                .overlay(
                                    VStack {
                                        Image(systemName: "photo")
                                            .font(.largeTitle)
                                        Text("图片 \(index)")
                                    }
                                )
                        }
                    }
                    .padding()
                }
                .frame(height: 150)
            }
            
            // 带滚动位置的滚动视图
            GroupBox("滚动位置追踪") {
                ScrollView {
                    VStack(spacing: 10) {
                        ForEach(1...30, id: \.self) { index in
                            Text("滚动位置: \(Int(scrollOffset))")
                                .font(.caption)
                                .padding()
                                .background(Color.blue.opacity(0.1))
                                .cornerRadius(8)
                                .overlay(
                                    GeometryReader { geometry in
                                        Color.clear
                                            .preference(key: ScrollOffsetKey.self,
                                                       value: geometry.frame(in: .global).minY)
                                    }
                                )
                        }
                    }
                    .padding()
                }
                .frame(height: 200)
                .onPreferenceChange(ScrollOffsetKey.self) { value in
                    scrollOffset = value
                }
            }
        }
        .padding()
        .navigationTitle("滚动视图")
    }
}

struct ScrollOffsetKey: PreferenceKey {
    static var defaultValue: CGFloat = 0
    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
        value = nextValue()
    }
}
  1. 高级功能

5.1 导航视图 (Views/AdvancedViews/NavigationViews.swift)

swift 复制代码
import SwiftUI

struct NavigationViews: View {
    var body: some View {
        NavigationView {
            List {
                NavigationLink("基础导航") {
                    BasicNavigationDetail()
                }
                
                NavigationLink("带工具栏的导航") {
                    ToolbarNavigationDetail()
                }
                
                NavigationLink("多级导航") {
                    MultiLevelNavigation()
                }
            }
            .navigationTitle("导航示例")
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button(action: {}) {
                        Image(systemName: "plus")
                    }
                }
            }
        }
    }
}

struct BasicNavigationDetail: View {
    var body: some View {
        VStack(spacing: 20) {
            Text("这是详细页面")
                .font(.largeTitle)
            
            NavigationLink("进入下一级") {
                Text("第三级页面")
                    .navigationTitle("第三级")
            }
        }
        .navigationTitle("详情")
        .navigationBarTitleDisplayMode(.inline)
    }
}

struct ToolbarNavigationDetail: View {
    @State private var isEditing = false
    
    var body: some View {
        List(1...20, id: \.self) { item in
            Text("项目 \(item)")
        }
        .navigationTitle("带工具栏")
        .toolbar {
            ToolbarItemGroup(placement: .navigationBarTrailing) {
                Button(action: { isEditing.toggle() }) {
                    Text(isEditing ? "完成" : "编辑")
                }
                
                Button(action: {}) {
                    Image(systemName: "trash")
                }
            }
            
            ToolbarItem(placement: .navigationBarLeading) {
                Button(action: {}) {
                    Image(systemName: "folder")
                }
            }
            
            ToolbarItem(placement: .bottomBar) {
                HStack {
                    Text("共20个项目")
                    Spacer()
                    Button("添加") {}
                }
            }
        }
    }
}

struct MultiLevelNavigation: View {
    var body: some View {
        List {
            NavigationLink("第一级") {
                List {
                    NavigationLink("第二级") {
                        Text("第三级 - 最终页面")
                            .navigationTitle("第三级")
                    }
                    .navigationTitle("第二级")
                }
                .navigationTitle("第一级详情")
            }
        }
        .navigationTitle("多级导航")
    }
}

5.2 手势识别 (Views/AdvancedViews/GestureViews.swift)

swift 复制代码
import SwiftUI

struct GestureViews: View {
    @State private var tapCount = 0
    @State private var longPressCount = 0
    @State private var dragOffset = CGSize.zero
    @State private var rotationAngle: Angle = .zero
    @State private var scale: CGFloat = 1.0
    @State private var swipeDirection = ""
    
    var body: some View {
        ScrollView {
            VStack(spacing: 30) {
                // 点击手势
                GroupBox("点击手势") {
                    VStack {
                        Text("点击次数: \(tapCount)")
                            .padding()
                            .background(Color.blue.opacity(0.2))
                            .cornerRadius(10)
                            .onTapGesture {
                                tapCount += 1
                            }
                        
                        Text("双击手势")
                            .padding()
                            .background(Color.green.opacity(0.2))
                            .cornerRadius(10)
                            .onTapGesture(count: 2) {
                                tapCount += 2
                            }
                    }
                    .frame(maxWidth: .infinity)
                    .padding()
                }
                
                // 长按手势
                GroupBox("长按手势") {
                    Text("长按次数: \(longPressCount)")
                        .padding()
                        .background(Color.orange.opacity(0.2))
                        .cornerRadius(10)
                        .onLongPressGesture(minimumDuration: 1) {
                            longPressCount += 1
                        }
                        .frame(maxWidth: .infinity)
                        .padding()
                }
                
                // 拖拽手势
                GroupBox("拖拽手势") {
                    Circle()
                        .fill(Color.blue)
                        .frame(width: 80, height: 80)
                        .offset(dragOffset)
                        .gesture(
                            DragGesture()
                                .onChanged { gesture in
                                    dragOffset = gesture.translation
                                }
                                .onEnded { _ in
                                    withAnimation(.spring()) {
                                        dragOffset = .zero
                                    }
                                }
                        )
                        .frame(maxWidth: .infinity)
                        .padding()
                    
                    Text("拖拽圆点试试")
                        .font(.caption)
                }
                
                // 旋转和缩放手势
                GroupBox("旋转和缩放手势") {
                    RoundedRectangle(cornerRadius: 20)
                        .fill(Color.purple.opacity(0.3))
                        .frame(width: 150, height: 150)
                        .rotationEffect(rotationAngle)
                        .scaleEffect(scale)
                        .gesture(
                            RotationGesture()
                                .onChanged { angle in
                                    rotationAngle = angle
                                }
                                .simultaneously(with: 
                                    MagnificationGesture()
                                        .onChanged { value in
                                            scale = value
                                        }
                                )
                        )
                        .onTapGesture(count: 2) {
                            withAnimation(.spring()) {
                                rotationAngle = .zero
                                scale = 1.0
                            }
                        }
                        .frame(maxWidth: .infinity)
                        .padding()
                    
                    Text("双指旋转或缩放,双击重置")
                        .font(.caption)
                }
                
                // 滑动手势
                GroupBox("滑动手势") {
                    Text("滑动方向: \(swipeDirection)")
                        .padding()
                        .frame(maxWidth: .infinity)
                        .background(Color.yellow.opacity(0.2))
                        .cornerRadius(10)
                        .gesture(
                            DragGesture(minimumDistance: 50)
                                .onEnded { gesture in
                                    let horizontal = gesture.translation.width
                                    let vertical = gesture.translation.height
                                    
                                    if abs(horizontal) > abs(vertical) {
                                        swipeDirection = horizontal > 0 ? "向右滑动" : "向左滑动"
                                    } else {
                                        swipeDirection = vertical > 0 ? "向下滑动" : "向上滑动"
                                    }
                                }
                        )
                        .padding()
                }
                
                // 组合手势
                GroupBox("组合手势") {
                    Rectangle()
                        .fill(Color.red.opacity(0.3))
                        .frame(height: 150)
                        .overlay(
                            VStack {
                                Image(systemName: "hand.tap")
                                    .font(.largeTitle)
                                Text("点击或拖拽")
                                    .font(.caption)
                            }
                        )
                        .gesture(
                            TapGesture()
                                .onEnded { _ in
                                    print("点击了")
                                }
                                .exclusively(before: 
                                    DragGesture()
                                        .onEnded { _ in
                                            print("拖拽了")
                                        }
                                )
                        )
                        .padding()
                }
            }
            .padding()
        }
        .navigationTitle("手势识别")
    }
}

这个教程涵盖了SwiftUI的主要布局功能,从基础的文本、图片、按钮,到复杂的布局容器和高级手势。每个部分都有详细的代码示例和实际应用场景。

相关推荐
T1an-16 小时前
最右IOS岗一面
ios
用户79457223954138 小时前
【RxSwift】Swift 版 ReactiveX,响应式编程优雅处理异步事件流
swift·rxswift
坏小虎8 小时前
Expo 快速创建 Android/iOS 应用开发指南
android·ios·rn·expo
光影少年9 小时前
Android和iOS原生开发的基础知识对RN开发的重要性,RN打包发布时原生端需要做哪些配置?
android·前端·react native·react.js·ios
北京自在科技9 小时前
Find My 修复定位 BUG,AirTag 安全再升级
ios·findmy·airtag
Digitally10 小时前
如何不用 USB 线将 iPhone 照片传到电脑?
ios·电脑·iphone
战族狼魂21 小时前
XCode 发起视频 和 收到视频通话邀请实现双语功能 中文和俄语
swift
Sim14801 天前
iPhone将内置本地大模型,手机端AI实现0 token成本时代来临?
人工智能·ios·智能手机·iphone
UXbot1 天前
2026年AI全链路产品开发工具对比:5款从创意到上线一站式平台深度解析
前端·ui·kotlin·软件构建·swift·原型模式