在SwiftUI中,根据需求弹出不同的Sheet

兄弟姐妹们在线分析下,在SwiftUI中,根据需求弹出不同的Sheet
最新回答
林中雨亭

2021-03-28 09:55:39

在SwiftUI中,根据需求弹出不同的Sheet,可以通过以下几种方式实现,每种方式都有其优缺点,开发者可以根据具体需求选择合适的方法。

1. 使用多个@State变量控制不同的Sheet

基本用法

@State var showView1 = false@State var showView2 = falseList { Button("View1") { showView1.toggle() } .sheet(isPresented: $showView1) { Text("View1") } Button("View2") { showView2.toggle() } .sheet(isPresented: $showView2) { Text("View2") }}

缺点

  • 需要声明多个@State变量来控制不同的Sheet。
  • 在复杂的视图结构中,可能无法正确激发Sheet的显示。
2. 使用sheet(item:)方法

优点

  • 只需要一个@State变量来控制不同的Sheet。
  • 可以动态切换不同的视图。

实现方式

struct View1: View { @Environment(.presentationMode) var presentationMode let text: String var body: some View { NavigationView { VStack { Text(text) Text("View1") } .toolbar { ToolbarItem(placement: .navigationBarLeading) { Button("cancel") { presentationMode.wrappedValue.dismiss() } } } } }}struct View2: View { @Environment(.presentationMode) var presentationMode var body: some View { NavigationView { Text("View2") .toolbar { ToolbarItem(placement: .navigationBarLeading) { Button("cancel") { presentationMode.wrappedValue.dismiss() } } } } }}struct SheetUsingAnyView: View { @State private var sheetView: AnyView? var body: some View { NavigationView { List { Button("View1") { sheetView = AnyView(View1(text: "Hello world")) } Button("View2") { sheetView = AnyView(View2()) } } .listStyle(InsetGroupedListStyle()) .sheet(item: $sheetView) { view in view } .navigationTitle("AnyView") .navigationBarTitleDisplayMode(.inline) } }}extension AnyView: Identifiable { public var id: UUID { UUID() }}

缺点

  • 在极个别情况下,当应用进入后台再返回时,可能会出现程序崩溃。
  • 代码可读性较差,尤其是当传入的视图参数较多时。
3. 使用枚举和sheet(item:)方法

优点

  • 避免了直接使用AnyView可能导致的崩溃问题。
  • 代码可读性更好,易于维护。

实现方式

struct SheetUsingEnum: View { @State private var sheetAction: SheetAction? var body: some View { NavigationView { List { Button("view1") { sheetAction = .view1(text: "Test") } Button("view2") { sheetAction = .view2 } } .listStyle(InsetGroupedListStyle()) .sheet(item: $sheetAction) { action in getActionView(action) } .navigationTitle("Enum") .navigationBarTitleDisplayMode(.inline) } } func getActionView(_ action: SheetAction) -> some View { switch action { case .view1(let text): return AnyView(View1(text: text)) case .view2: return AnyView(View2()) } }}enum SheetAction: Identifiable { case view1(text: String) case view2 var id: UUID { UUID() }}

优点

  • 避免了崩溃问题。
  • 代码结构清晰,易于理解和维护。
4. 解决某些视图无法激活Sheet的问题

在某些复杂的视图结构中,可能无法直接激活Sheet。可以通过绑定父视图的sheetAction来间接激活Sheet。

实现方式

struct ParentView: View { @State private var sheetAction: SheetAction? var body: some View { ChildView(sheetAction: $sheetAction) .sheet(item: $sheetAction) { action in getActionView(action) } } func getActionView(_ action: SheetAction) -> some View { switch action { case .view1(let text): return AnyView(View1(text: text)) case .view2: return AnyView(View2()) } }}struct ChildView: View { @Binding var sheetAction: SheetAction? var body: some View { Button("Show View1") { sheetAction = .view1(text: "From Child") } }}总结

在SwiftUI中,根据需求弹出不同的Sheet,可以通过以下几种方式实现:

  1. 使用多个@State变量:简单直接,但需要管理多个状态变量,且在复杂视图结构中可能无法正确激发Sheet。
  2. 使用sheet(item:)和AnyView:代码简洁,但可能存在崩溃风险,且代码可读性较差。
  3. 使用枚举和sheet(item:):推荐方式,避免了崩溃问题,代码结构清晰,易于维护。
  4. 绑定父视图的sheetAction:解决复杂视图结构中无法直接激活Sheet的问题。

开发者可以根据具体需求和场景选择合适的方法,推荐使用枚举和sheet(item:)的方式,以获得更好的代码结构和稳定性。