You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI 如何在VStack中布局多个可触发Sheet的视图按钮

可直接运行的实现代码
import SwiftUI

// 通用弹窗内容视图
struct SecondView: View {
    var name: String
    var body: some View {
        Text("当前分类:\(name)")
            .font(.largeTitle)
    }
}

// 统一管理所有Sheet类型
enum SheetItem: Identifiable {
    case mainDish, dessert, drink, setMeal
    // 遵循Identifiable协议必填
    var id: Self { self }
    // 对应弹窗要显示的分类名称
    var displayName: String {
        switch self {
        case .mainDish: return "主菜"
        case .dessert: return "甜点"
        case .drink: return "饮品"
        case .setMeal: return "套餐"
        }
    }
}

struct ContentView: View {
    // 存储当前选中的弹窗类型,为nil时不弹出
    @State private var selectedSheet: SheetItem?
    
    var body: some View {
        // 所有按钮放在VStack中布局
        VStack(spacing: 20) {
            Button("主菜菜单") {
                selectedSheet = .mainDish
            }
            .buttonStyle(MenuButtonStyle(backgroundImage: "bg"))
            
            Button("甜点菜单") {
                selectedSheet = .dessert
            }
            .buttonStyle(MenuButtonStyle(backgroundImage: "bg"))
            
            Button("饮品菜单") {
                selectedSheet = .drink
            }
            .buttonStyle(MenuButtonStyle(backgroundImage: "bg"))
            
            Button("套餐菜单") {
                selectedSheet = .setMeal
            }
            .buttonStyle(MenuButtonStyle(backgroundImage: "bg"))
        }
        // 统一挂载Sheet修饰符
        .sheet(item: $selectedSheet) { item in
            SecondView(name: item.displayName)
                .padding()
        }
        // 调整整个VStack的位置,替代原来单个Button的position
        .position(x: UIScreen.main.bounds.width/2, y: 250)
    }
}

// 抽离公共按钮样式,避免重复代码
struct MenuButtonStyle: ButtonStyle {
    var backgroundImage: String
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .foregroundColor(.white)
            .font(Font.largeTitle.weight(.bold))
            .frame(width: 300, height: 80, alignment: .leading)
            .padding(.leading, 20)
            .background(
                Image(backgroundImage)
                    .resizable()
                    .scaledToFill()
            )
            .cornerRadius(12)
            .opacity(configuration.isPressed ? 0.8 : 1)
    }
}
关键说明
  • 用遵循Identifiable协议的枚举管理所有弹窗类型,避免声明多个Bool状态变量引发的状态冲突、布局报错
  • Sheet修饰符统一挂载在VStack容器上,不要重复挂载到每个Button上,是SwiftUI多Sheet场景的官方推荐实现方式
  • 公共按钮样式抽离为ButtonStyle,新增按钮时直接复用样式即可,代码更易维护

内容的提问来源于stack exchange,提问作者Zidaan Tumbi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 20:48:03