I am writing a SwiftUI framework package where I want to have some APIs that allow presentation of a view. For these views, I always want them presented above the presenting view as a modal sheet view (I want to disallow having these views embedded as a subview in an app's view).
Apple appears to have very few system APIs like this, but I have found this API - which behaves as I expect:
public func fileImporter(isPresented: Binding<Bool>, allowedContentTypes: [UTType], onCompletion: @escaping (_ result: Result<URL, Error>) -> Void) -> some View
Note that Apple has implemented this as a View
extension, so you can simply use like so:
Button("Import..") {
self.showingFileImporter = true
}
.fileImporter(isPresented: $showingFileImporter, allowedContentTypes: [.pdf]) { result in
// got result
}
So, I'm trying to use this pattern to implement my own API, something like:
func mySomethingSelector(isPresented: Binding<Bool>, completion: @escaping () -> Void) -> some View
However, I'm unsure how to start the implementation. The first thing I noticed is that fileImporter
actually returns some View
, but this is not the screen that's actually presented. So, we need to return some kind of wrapper view, that then presents above the wrapper view? (Note that I assume that Apple has actually implemented fileImporter
by bridging to UIKit - and possibly out of process. But I just want to use standard SwiftUI for my implementation).
Anyway, hopefully this makes sense. Any guidance appreciated.
CodePudding user response:
A very simple implementation might look like this, using a sheet
to display your custom View
:
struct ContentView: View {
@State private var isPresented: Bool = false
var body: some View {
Button("Present") {
isPresented.toggle()
}
.mySomethingSelector(isPresented: $isPresented) {
print("Done")
}
}
}
extension View {
func mySomethingSelector(isPresented: Binding<Bool>, completion: @escaping () -> Void) -> some View {
self.sheet(isPresented: isPresented, onDismiss: completion) {
Text("My View")
}
}
}