簡體   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