swiftuionhover

How to apply .onHover to individual elements in SwiftUI


I am trying to animate individual items on mouseover. The issue I am having is that every item gets animated on mouseover of an item instead of just that specific item. Here is what I have:

struct ContentView : View {
    @State var hovered = false
    var body: some View {
        VStack(spacing: 90) {
            ForEach(0..<2) {_ in
                HStack(spacing: 90) {
                    ForEach(0..<4) {_ in
                        Circle().fill(Color.red).frame(width: 50, height: 50)
                            .scaleEffect(self.hovered ? 2.0 : 1.0)
                        .animation(.default)
                        .onHover { hover in
                                print("Mouse hover: \(hover)")
                            self.hovered.toggle()
                        }
                    }
                }
            }
        }
        .frame(minWidth:300,maxWidth:.infinity,minHeight:300,maxHeight:.infinity)
    }
}




drawing


Solution

  • It needs to change onHover view on per-view base, ie. store some identifier of hovered view.

    Here is possible solution. Tested with Xcode 11.4.

    demo

    struct TestOnHoverInList : View {
        @State var hovered: (Int, Int) = (-1, -1)
        var body: some View {
            VStack(spacing: 90) {
                ForEach(0..<2) {i in
                    HStack(spacing: 90) {
                        ForEach(0..<4) {j in
                            Circle().fill(Color.red).frame(width: 50, height: 50)
                            .scaleEffect(self.hovered == (i,j) ? 2.0 : 1.0)
                            .animation(.default)
                            .onHover { hover in
                                print("Mouse hover: \(hover)")
                                if hover {
                                    self.hovered = (i, j)    // << here !!
                                } else {
                                    self.hovered = (-1, -1)  // reset
                                }
                            }
                        }
                    }
                }
            }
            .frame(minWidth:300,maxWidth:.infinity,minHeight:300,maxHeight:.infinity)
        }
    }