Creating Multiple Sheets in SwiftUI

Learn how to display multiple dialogs and modals in SwiftUI using boolean bindings or Identifiable items

Creating Multiple Sheets in SwiftUI

To display modals or dialogs in SwiftUI, you can use the sheet feature in two ways. You can use a boolean binding as follows:

func sheet<Content>(
    isPresented: Binding<Bool>,
    onDismiss: (() -> Void)? = nil,
    content: @escaping () -> Content
) -> some View where Content : View

Or you can use an Identifiable item binding like this:

func sheet<Item, Content>(
    item: Binding<Item?>,
    onDismiss: (() -> Void)? = nil,
    content: @escaping (Item) -> Content
) -> some View wh

You can use both approaches as needed, and even combine them.

#Displaying Multiple Modals/Dialogs with Boolean Binding

To display multiple modals/dialogs using boolean bindings, the process is straightforward. Simply add multiple state variables of type boolean and attach the .sheet modifier for each. Here's an example:

import SwiftUI

struct ContentView: View {
   
    @State private var mdl1: Bool = false
    @State private var mdl2: Bool = false

    var body: some View {
        VStack {
            HStack {
                Button("Modal 1") {
                    mdl1 = true
                }
                
                Button("Modal 2") {
                    mdl2 = true
                }
            }
           
        }
        .padding()
        .sheet(isPresented: $mdl1) {
            Text("Modal 1")
        }
        .sheet(isPresented: $mdl2) {
            Text("Modal 2")
        }
    }
}

This method is quite simple but is suitable for showcasing a limited number of modals/dialogs, typically less than three, as the number of variables and sheet modifiers increases with each modal/dialog.

#Displaying Multiple Modals/Dialogs with Identifiable Binding

Another alternative for displaying multiple modals/dialogs is by using an Identifiable item binding, as demonstrated below:

struct ContentView: View {
    enum ActiveSheet: Identifiable {
        case modal3, modal4, modal5

        var id: Int {
            hashValue
        }
    }

    @State private var mdl: ActiveSheet?

    var body: some View {
        VStack {
            HStack {
                Button("Modal 3") {
                    mdl = .modal3
                }
                Button("Modal 4") {
                    mdl = .modal4
                }
                Button("Modal 5") {
                    mdl = .modal5
                }
            }
        }
        .padding()
        .sheet(item: $mdl, content: { item in
            switch item {
            case .modal3: Text("Modal 3")
            case .modal4: Text("Modal 4")
            case .modal5: Text("Modal 5")
            }
        })
    }
}

To replace the role of multiple boolean state variables, we create an enum that conforms to the Identifiable protocol. To meet the requirements of the Identifiable protocol, we derive the ID from the hashValue. We then create a single state variable, in this case, mdl, to store the active modal.

enum ActiveSheet: Identifiable {
	case modal3, modal4, modal5

	var id: Int {
		hashValue
	}
}
@State private var mdl: ActiveSheet?

This approach simplifies the code significantly, as you only need one .sheet modifier, and the content is displayed based on the active type.

.sheet(item: $mdl, content: { item in
	switch item {
        case .modal3: Text("Modal 3")
        case .modal4: Text("Modal 4")
        case .modal5: Text("Modal 5")
	}
})

One crucial thing to note here is that all cases must be exhaustive. That means you must list all possible cases. If you don't, you'll encounter a Swift error stating that it must be exhaustive.

The advantage of using Identifiable binding is that the code becomes simpler, and you don't need multiple .sheet modifiers. This method is particularly suitable when you want to display numerous modals/dialogs, typically more than three.

GitHub - meshwara/SwiftUI-Multiple-Sheet
Contribute to meshwara/SwiftUI-Multiple-Sheet development by creating an account on GitHub.

Good luck, and hopefully this little bit is useful.

Reference:
developer.apple.com