如果鼠标移动太快,SwiftUI onHover 不会注册鼠标离开元素 [英] SwiftUI onHover doesn't register mouse leaving the element if mouse moves too fast

查看:33
本文介绍了如果鼠标移动太快,SwiftUI onHover 不会注册鼠标离开元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 SwiftUI 中制作了一些根据悬停状态改变外观的自定义滑块视图,但是如果鼠标移出太快(这实际上是移动光标的非常合理的速度),它会保持悬停状态直到您重新悬停并缓慢地重新离开组件.

I've made some custom slider views in SwiftUI that change appearance based on hover state, but if the mouse moves out too fast (which is actually a very reasonable speed of moving a cursor), it stays in the hover state until you re-hover and re-leave the component slowly.

有没有办法解决这个问题?悬停代码非常标准:

Is there a solution for this? The hover code is pretty standard:

struct RulerSlider: View {
  @State var hovering = false

  var body: some View {
    GeometryReader { geometry in
      ZStack {
        // Ruler lines
        if hovering {
          Ruler()
        }
      }
      .onHover { hover in
        withAnimation(.easeOut(duration: 0.1)) {
          self.hovering = hover
        }
      }
    }
  }
}

问题如下:

重现错误的示例代码:https://gist.github.com/rdev/ea0c53448e12835b29faa11fec8e0388>

推荐答案

我今天解决了这个问题,在一个空的 NSView 上有一个跟踪区域.这是在半复杂且快速刷新的网格视图中进行测试的,该视图以前具有与您想象的相同的行为.大约 75 个视图在 此要点中的 GIF 捕获 中应用了此修饰符,大多数视图对每个视图都具有零边框其他.

I resolved this issue today with a tracking area on an empty NSView. This is tested in a semi-complex and quickly refreshing grid view, which previously had the same behavior you pictured. About 75 views have this modifier applied in the GIF capture in this gist, most with zero border to each other.

import SwiftUI

extension View {
    func whenHovered(_ mouseIsInside: @escaping (Bool) -> Void) -> some View {
        modifier(MouseInsideModifier(mouseIsInside))
    }
}

可表示为空跟踪视图

struct MouseInsideModifier: ViewModifier {
    let mouseIsInside: (Bool) -> Void
    
    init(_ mouseIsInside: @escaping (Bool) -> Void) {
        self.mouseIsInside = mouseIsInside
    }
    
    func body(content: Content) -> some View {
        content.background(
            GeometryReader { proxy in
                Representable(mouseIsInside: mouseIsInside,
                              frame: proxy.frame(in: .global))
            }
        )
    }
    
    private struct Representable: NSViewRepresentable {
        let mouseIsInside: (Bool) -> Void
        let frame: NSRect
        
        func makeCoordinator() -> Coordinator {
            let coordinator = Coordinator()
            coordinator.mouseIsInside = mouseIsInside
            return coordinator
        }
        
        class Coordinator: NSResponder {
            var mouseIsInside: ((Bool) -> Void)?
            
            override func mouseEntered(with event: NSEvent) {
                mouseIsInside?(true)
            }
            
            override func mouseExited(with event: NSEvent) {
                mouseIsInside?(false)
            }
        }
        
        func makeNSView(context: Context) -> NSView {
            let view = NSView(frame: frame)
            
            let options: NSTrackingArea.Options = [
                .mouseEnteredAndExited,
                .inVisibleRect,
                .activeInKeyWindow
            ]
            
            let trackingArea = NSTrackingArea(rect: frame,
                                              options: options,
                                              owner: context.coordinator,
                                              userInfo: nil)
            
            view.addTrackingArea(trackingArea)
            
            return view
        }
        
        func updateNSView(_ nsView: NSView, context: Context) {}
        
        static func dismantleNSView(_ nsView: NSView, coordinator: Coordinator) {
            nsView.trackingAreas.forEach { nsView.removeTrackingArea($0) }
        }
    }
}

这篇关于如果鼠标移动太快,SwiftUI onHover 不会注册鼠标离开元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆