[英]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.