SwiftUI:支持多种模式

kee*_*n3d 16 swift swiftui

我正在尝试设置一个视图,该视图可以显示多个模式,具体取决于所点击的按钮。

当我只添加一个时sheet,一切正常:

.sheet(isPresented: $showingModal1) { ... }
Run Code Online (Sandbox Code Playgroud)

但是,当我添加另一张纸时,只有最后一张可用。

.sheet(isPresented: $showingModal1) { ... }
.sheet(isPresented: $showingModal2) { ... }
Run Code Online (Sandbox Code Playgroud)

更新

我试图使此工作正常,但是我不确定如何为声明类型modal。我收到的错误Protocol 'View' can only be used as a generic constraint because it has Self or associated type requirements

struct ContentView: View {
    @State var modal: View?
    var body: some View {
        VStack {
            Button(action: {
                self.modal = ModalContentView1()
            }) {
                Text("Show Modal 1")
            }
            Button(action: {
                self.modal = ModalContentView2()
            }) {
                Text("Show Modal 2")
            }
        }.sheet(item: self.$modal, content: { modal in
            return modal
        })
    }
}

struct ModalContentView1: View {
    var body: some View {
        Text("Modal 1")
    }
}

struct ModalContentView2: View {
    var body: some View {
        Text("Modal 2")
    }
}
Run Code Online (Sandbox Code Playgroud)

kon*_*iki 17

也许我错过了要点,但是您可以通过一次调用.sheet()或多次调用来实现。

多种.sheet()方法:

import SwiftUI

struct MultipleSheets: View {
    @State private var sheet1 = false
    @State private var sheet2 = false
    @State private var sheet3 = false

    var body: some View {
        VStack {

            Button(action: {
                self.sheet1 = true
            }, label: { Text("Show Modal #1") })
            .sheet(isPresented: $sheet1, content: { Sheet1() })

            Button(action: {
                self.sheet2 = true
            }, label: { Text("Show Modal #2") })
            .sheet(isPresented: $sheet2, content: { Sheet2() })

            Button(action: {
                self.sheet3 = true
            }, label: { Text("Show Modal #3") })
            .sheet(isPresented: $sheet3, content: { Sheet3() })

        }
    }
}

struct Sheet1: View {
    var body: some View {
        Text("This is Sheet #1")
    }
}

struct Sheet2: View {
    var body: some View {
        Text("This is Sheet #2")
    }
}

struct Sheet3: View {
    var body: some View {
        Text("This is Sheet #3")
    }
}
Run Code Online (Sandbox Code Playgroud)

单个.sheet()方法:

struct MultipleSheets: View {
    @State private var showModal = false
    @State private var modalSelection = 1

    var body: some View {
        VStack {

            Button(action: {
                self.modalSelection = 1
                self.showModal = true
            }, label: { Text("Show Modal #1") })

            Button(action: {
                self.modalSelection = 2
                self.showModal = true
            }, label: { Text("Show Modal #2") })

            Button(action: {
                self.modalSelection = 3
                self.showModal = true
            }, label: { Text("Show Modal #3") })

        }
        .sheet(isPresented: $showModal, content: {
            if self.modalSelection == 1 {
                Sheet1()
            }

            if self.modalSelection == 2 {
                Sheet2()
            }

            if self.modalSelection == 3 {
                Sheet3()
            }
        })

    }
}

struct Sheet1: View {
    var body: some View {
        Text("This is Sheet #1")
    }
}

struct Sheet2: View {
    var body: some View {
        Text("This is Sheet #2")
    }
}

struct Sheet3: View {
    var body: some View {
        Text("This is Sheet #3")
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这在 iOS 14 上不再适用。在第一种情况下,视图中的最后一个工作表修改器将覆盖所有其他工作表(即第三个按钮工作表)。在第二种情况下,默认工作表(即 modalSelection 为 1)将在第一次按钮点击时加载,即使选择了 modalSelection 为 2。 (6认同)
  • 嗯,第一个解决方案对我不起作用。显示第一个模态后,其他任何按钮均无法显示其他模态 (3认同)
  • 这也对我有用。但是问题似乎出在当您在具有任何子视图已经调用`.sheet()的父视图上调用`.sheet()`时。因此,在发布的第一个示例@kontiki中,在`VStack`上调用`.sheet()`不允许为`Button`视图调用`.sheet()`。 (3认同)
  • 这可行,但似乎不是一个解决方案。我从来没有想到要在按钮本身上使用 .sheet 修饰符。 (2认同)

car*_*ath 13

我不确定这是否总是可能的,但在 Xcode 11.3.1 中,.sheet()对于这个用例(https://developer.apple.com/documentation/swiftui/view/3352792-sheet)有一个过载。您可以使用 Identifiable 项目而不是 bool 来调用它:

struct ModalA: View {

    var body: some View {
        Text("Hello, World! (A)")
    }

}

struct ModalB: View {

    var body: some View {
        Text("Hello, World! (B)")
    }

}

struct MyContentView: View {

    enum Sheet: Hashable, Identifiable {

        case a
        case b

        var id: Int {
            return self.hashValue
        }

    }

    @State var activeSheet: Sheet? = nil

    var body: some View {
        VStack(spacing: 42) {
            Button(action: {
                self.activeSheet = .a
            }) {
                Text("Hello, World! (A)")
            }
            Button(action: {
                self.activeSheet = .b
            }) {
                Text("Hello, World! (B)")
            }
        }
            .sheet(item: $activeSheet) { item in
                if item == .a {
                    ModalA()
                } else if item == .b {
                    ModalB()
                }
            }
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 这是我使用的方法。效果很好。 (2认同)
  • 这效果很好,可能应该是公认的答案!作为奖励,如果您使用的是 Xcode 12,则可以使用 switch 语句而不是 if 语句来获取工作表的正确视图。 (2认同)

pli*_*sey 6

这有效:

.background(EmptyView().sheet(isPresented: $showingModal1) { ... }
   .background(EmptyView().sheet(isPresented: $showingModal2) { ... }))
Run Code Online (Sandbox Code Playgroud)

注意这些是如何嵌套的backgrounds。没有两个背景一个接一个。

感谢DevAndArtist找到了这个。

  • 出色的!!奇迹般有效! (5认同)
  • 很棒的技巧,我不确定这是否是解决这个问题的正确方法,但它保持如此干净。 (5认同)
  • 我根据这个答案写了一个小库,大大简化了语法 https://github.com/davdroman/MultiSheet (2认同)