Search code examples
swiftuiios16

Adding Shadow to LazyHGrid Element Selection


I have an app in which the user may select a SF icon from those within a LazyHGrid. I would like to add a shadow around the selected icon and remove the shadow when deselected.

Currently, the working code below may be used to scroll the available icons and select an icon by tapping. I need help changing the view to support applying shadow to the selected element.

I tried placing the same image() and modifiers within the button action but got a Xcode warning that the ZStack initializer is unused. I also tried adding a shadow modifier to the view changing the shadow parameters with state properties set in the button action area. This applied shadow to all elements in LazyHGrid. I want the shadow applied only to the selected element.

 struct ImageStore: Identifiable, Hashable {

    var iconName: String
    var id: Int
}

struct ContentView: View {

    let rows = [
        GridItem(.flexible()),
    ]

    let colors: [Color] = [.green, .red, .yellow, .blue]

    let imageName = [
        ImageStore(iconName: "a.square.fill", id: 0),
        ImageStore(iconName: "b.square.fill", id: 1),
        ImageStore(iconName: "c.square.fill", id: 2),
        ImageStore(iconName: "d.square.fill", id: 3),
        ImageStore(iconName: "e.square.fill", id: 4),
        ImageStore(iconName: "f.square.fill", id: 5),
        ImageStore(iconName: "g.square.fill", id: 6),
    ]

    @State private var selectedIcon: Int = 0

    var body: some View {

        VStack {
            ScrollView (.horizontal) {
                LazyHGrid( rows: rows, spacing: 20) {
                    ForEach(imageName, id: \.self) { image in

                        Button( action: {

                            selectedIcon = image.id

                            print("image name = \(image.iconName)")
                            print("id = \(image.id)")
                            print("selectedIcon = \(selectedIcon)")

                        }){

                            Image(systemName: image.iconName)
                                .font(.largeTitle)
                                .foregroundColor(.white)
                                .padding()
                                .background(colors[image.id % colors.count])
                        }
                    }
                }
            }
        }
    }
}

Solution

  • Perhaps I'm not understanding your question fully, but it should be as simple as using the .shadow modifier with a ternary expression, e.g.

    .shadow(radius: selectedIcon == image.id ? 5 : 0)
    

    to make sure the image doesn't have it's own shadow in addition to the background, add a .drawingGroup modifier, e.g

    Button {
       selectedIcon = image.id
    } label: {
       Image(systemName: image.iconName)
           .font(.largeTitle)
           .foregroundColor(.white)
           .padding()
           .background(colors[image.id % colors.count])
    
           .drawingGroup()
           .shadow(radius: selectedIcon == image.id ? 5 : 0)
    }
    

    enter image description here