This gist accompanies a blog post on Masilotti.com, How to manage multiple sheets in SwiftUI.
-
-
Save joemasilotti/b90d89cc8e78440bf21c25ce512a72b1 to your computer and use it in GitHub Desktop.
| class SettingsSheet: SheetState<SettingsSheet.State> { | |
| enum State { | |
| case attributions | |
| case email | |
| case feedback | |
| case instructions | |
| case licenseAgreement | |
| case privacyPolicy | |
| } | |
| } |
| struct SettingsView: View { | |
| @ObservedObject var sheet = SettingsSheet() | |
| var body: some View { | |
| VStack { | |
| Button("Attributions") { self.sheet.state = .attributions } | |
| Button("Email") { self.sheet.state = .email } | |
| Button("Feedback") { self.sheet.state = .feedback } | |
| Button("Instructions") { self.sheet.state = .instructions } | |
| Button("License Agreement") { self.sheet.state = .licenseAgreement } | |
| Button("Privacy Policy") { self.sheet.state = .privacyPolicy } | |
| } | |
| .sheet(isPresented: $sheet.isShowing, content: sheetContent) | |
| } | |
| @ViewBuilder | |
| private func sheetContent() -> some View { | |
| if sheet.state == .attributions { | |
| AttributionsView() | |
| } else if sheet.state == .email { | |
| EmailView() | |
| } else if sheet.state == .feedback { | |
| FeedbackView() | |
| } else if self.sheet.state == .instructions { | |
| InstructionsView() | |
| } else if self.sheet.state == .licenseAgreement { | |
| WebView(url: Policy.licenseURL) | |
| } else if self.sheet.state == .privacyPolicy { | |
| WebView(url: Policy.privacyURL) | |
| } else { | |
| EmptyView() | |
| } | |
| } | |
| } |
| import Combine | |
| class SheetState<State>: ObservableObject { | |
| @Published var isShowing = false | |
| @Published var state: State? { | |
| didSet { isShowing = state != nil } | |
| } | |
| } |
also I guess in the buttons you were mean to write
Button("Attributions") { self.sheet.state = .attributions }Thanks @fespinoza.
You're correct, I updated the gist. Great catch!
I like your solution. How would you best implement a “Done” button inside the sheet? Pass $sheet.isShowing as Binding to the SheetView?
Exactly, @UlricusR! I'm doing the same for a confirmation button in a form-style sheet.
As I still had issues with conflicting Bindings to other Observable Objects with your final and your pre-final solution (the one without the SheetState class), I posted this on StackOverflow with a - in my eyes - very elegant solution, as you can even get rid of the SheetState class this way:
https://stackoverflow.com/questions/64139912/swiftui-state-property-is-not-updated
To close the sheet, I followed this post:
https://daddycoding.com/2020/03/01/swiftui-sheet-modals/
At the end, I combined your solution with the other two. Thanks again!
Very nice! Do you have a version for iOS 13?
Well, the App I use it for has target iOS 13.5 and above, so yes, it should work for iOS 13. You can see it in action e.g. in FoodList.swift in my repo https://github.com/UlricusR/iOS-EasyFPU
well written post/examples!