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
相关产品推荐
相关产品推荐

