DEV Community

Nicola De Filippo
Nicola De Filippo

Posted on

SwiftUI Sheets Demystified (Episode II )

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
}
Enter fullscreen mode Exit fullscreen mode

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)
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

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()
                }
            }
        ).edgesIgnoringSafeArea(.all)
            .background(
                color?.value ?? .white
            )
    }
}
Enter fullscreen mode Exit fullscreen mode

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
)
Enter fullscreen mode Exit fullscreen mode

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())
Enter fullscreen mode Exit fullscreen mode

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)
}
Enter fullscreen mode Exit fullscreen mode
  • Note: English is not my native language, so I’m sorry for some errors. I appreciate if your correct me.* Originally posted

Top comments (0)