In the previous episode (SwiftUI Sheets Demystified (Episode I°)), we learned how to open a sheet. In this episode, we will learn how to open the sheet by passing a selected value. Here’s a brief overview of what we’ll cover:
- Selecting a color name from a list, passing the selected color to the sheet, and using it as the background color.
- How to tap a row in a list that has an empty zone
First, let’s define the color struct:
struct IColor: Identifiable { let id = UUID() var name: String var value: Color }
This struct implements the Identifiable protocol so we add the id identifier. The name contains the color name, instead the value the color.
Now, let’s take a look at the ContentView::
struct ContentView: View { var colors = [IColor(name: "red", value: .red), IColor(name: "blue", value: .blue), IColor(name: "green", value: .green)] @State var colorSelected: IColor? var body: some View { NavigationStack { List{ ForEach(colors) { color in HStack() { Text(color.name) Spacer() }.contentShape(Rectangle()) .onTapGesture { colorSelected = color } } }.sheet(item: $colorSelected) { color in SheetUIView(color: $colorSelected) } } } }
We have a list of three colors. We define a state variable colorSelected
as an optional because initially, no color is selected.
The list of colors is displayed using a horizontal stack comprising a Text
and a Spacer
(to fill the entire row of the list).
We define the onTapGesture
to set colorSelected
to the chosen color. Then, the sheet is opened when the colorSelected
variable changes its value. In this case, it opens with the SheetUIView
that receives the selected color.
The SheetUIView is this:
struct SheetUIView: View { @Environment(\.dismiss) private var dismiss @Binding var color: IColor? var body: some View { ScrollView { }.overlay( HStack { Spacer() VStack { Button(action: { dismiss() }, label: { Image(systemName: "chevron.down.circle.fill") .font(.largeTitle) .foregroundColor(.white) }) .padding(.trailing, 20) .padding(.top, 10) Spacer() } } ).ignoresSafeArea(.all) .background( color?.value ?? .white ) } }
The view is identical to that of the first episode, with only two differences: the image has been removed for brevity, and it’s added the
.background( color?.value ?? .white )
Note that the default color value is set to white. It’s essential to define a default value not only for when the sheet is opened, but also for when it’s closed. Without a default value, the selected color would be null when the sheet is closed, potentially causing the app to crash.
One consideration to keep in mind, take a look in the ContentView at:
.contentShape(Rectangle())
It’s necessary to make the entire row clickable. If we omit this, only the text area of the row will be clickable.
To conclude, in the SheetUIView
, use the following preview instruction to avoid errors:
#Preview { @State var color: IColor? = IColor(name: "white", value: .white) return SheetUIView(color: $color) }
Note: English is not my native language, so I’m sorry for some errors. I appreciate if your correct me.
1 comment