繁体   English   中英

如何将.onHover应用于SwiftUI中的单个元素

[英]How to apply .onHover to individual elements in SwiftUI

我正在尝试在鼠标悬停时为单个项目设置动画。 我遇到的问题是,每个项目都会在鼠标悬停在某个项目上而不只是那个特定项目上时得到动画。 这是我所拥有的:

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)
    }
}




画画

当前每个项目都会被动画化,因为它们都依赖hovered来查看Circle是否悬停。 为了解决这个问题,我们可以让每个圆圈都有自己hovered的 state。

struct CircleView: View {
    @State var hovered = false

    var body: some View {
        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()
        }
    }
}

ForEach中,我们可以调用新的CircleView ,其中每个Circle都有自己的事实来源。

struct ContentView : View {
    var body: some View {
        VStack(spacing: 90) {
            ForEach(0..<2) { _ in
                HStack(spacing: 90) {
                    ForEach(0..<4) { _ in
                        CircleView()
                    }
                }
            }
        }
        .frame(minWidth:300,maxWidth:.infinity,minHeight:300,maxHeight:.infinity)
    }
}

它需要在每个视图基础上更改 onHover 视图,即。 存储一些悬停视图的标识符。

这是可能的解决方案。 使用 Xcode 11.4 进行测试。

演示

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)
    }
}

备份

或者,您可以创建一个修改器,允许您在鼠标悬停时更改有问题的视图:

extension View {
    func onHover<Content: View>(@ViewBuilder _ modify: @escaping (Self) -> Content) -> some View {
        modifier(HoverModifier { modify(self) })
    }
}

private struct HoverModifier<Result: View>: ViewModifier {
    @ViewBuilder let modifier: () -> Result
    @State private var isHovering = false

    func body(content: Content) -> AnyView {
        (isHovering ? modifier().eraseToAnyView() : content.eraseToAnyView())
            .onHover { self.isHovering = $0 }
            .eraseToAnyView()
    }
}

那么你的例子中的每个 Circle 都会是 go 这样的:

Circle().fill(Color.red).frame(width: 50, height: 50)
    .animation(.default)
    .onHover { view in
        _ = print("Mouse hover")
        view.scaleEffect(2.0)
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM