gpt4 book ai didi

xcode - SwiftUI:如何在水平 ScrollView 中监听鼠标滚轮滚动事件

转载 作者:行者123 更新时间:2023-12-04 13:11:39 29 4
gpt4 key购买 nike

我正在开发一个macos软件,我发现在swiftui中scrollview设置为.horizo​​ntal,所以当鼠标滚轮滚动时列表不会滚动,但在.vertical 模式。

但我确实需要这个功能。

所以我尝试了一个选项:实现 NSViewRepresentable 以使 NSView 覆盖 scrollWheel 可以处理鼠标滚轮滚动事件的方法。然后发布通知。

struct MouseWheelScrollEventView : NSViewRepresentable {

class MouseView : NSView {
override var acceptsFirstResponder: Bool {
true
}

override func acceptsFirstMouse(for event: NSEvent?) -> Bool {
return true
}

override func scrollWheel(with event: NSEvent) {
NotificationCenter.default.post(name: Notification.Name("mouseevent"), object: event)
}
}


func makeNSView(context: Context) -> some NSView {
let view = MouseView()

DispatchQueue.main.async {
view.window?.makeFirstResponder(view)
}
return view
}

func updateNSView(_ nsView: NSViewType, context: Context) {
print("update")
}
}

然后在 SwiftUI 中,代码如下:

@available(OSX 11.0, *)
struct ContentView: View {

let mouseWheelScrollEventPublisher = NotificationCenter.default.publisher(for: Notification.Name(rawValue: "mouseevent"))

@State var deltaY = 0.0

@State var currentIndex = 1

var body: some View{

ZStack{
ScrollView(.horizontal,showsIndicators:false) {
ScrollViewReader { value in

LazyHStack(alignment: .top) {
ForEach(1...100, id: \.self) { index in

if(self.currentIndex == index) {
Text("\(String(index))")
.frame(width: 80, height: 80)
.background(Color.yellow)
.onTapGesture(perform: {
print(index)
})
}else {
Text("\(String(index))")
.frame(width: 80, height: 80)
.background(Color.blue)
.onTapGesture(perform: {
print(index)
})
}
}
}
.onReceive(mouseWheelScrollEventPublisher) { output in
let event = output.object as! NSEvent
let deltaY = event.deltaY

if(deltaY < 0 && self.currentIndex < 100) {
self.currentIndex += 1
value.scrollTo(currentIndex)
}else if(deltaY > 0 && self.currentIndex > 1) {
self.currentIndex -= 1
value.scrollTo(currentIndex)
}

}
}
}
.frame(width: 600)

MouseWheelScrollEventView()
}
}

}

现在滚动事件可以在.horizo​​ntalscrollView中处理,但是有一个新问题:scrollViewItem不能处理点击事件,因为MouseWheelScrollEventView处理鼠标点击事件。但是我希望scrollViewItem也能处理鼠标点击事件。

如何处理鼠标滚轮滚动事件和点击事件?

ps:我知道使用appkit可以解决问题,但是有什么办法可以尝试使用swiftui实现吗?

最佳答案

您可以简单地监听应用的 currentEvent 并在以下情况下跳过窥探的 NSViewRep:

  • 您已经为 View 设置了一个悬停/焦点 bool 值
  • 不需要 NSTrackingArea 来限制响应(例如,用户希望始终与之交互的 transient 弹出窗口中只有一个 ScrollView)

下面是我的一个 macOS SwiftUI 应用程序中的 transient 弹出窗口示例。水平 ScrollView 呈现选项,可以通过缓慢或快速垂直滚动来“滚动选择”。您可以插入 ScrollViewProxy 以获得相同的想法。

在测试实现中,使用 .onReceive() {} 会重新计算 View ,并且单个鼠标滚动会重复触发。将订阅存储在 @State 变量中可以让它按需要工作。

    //horizontal scroll view   
.onAppear { trackScrollWheel() }

func trackScrollWheel() {
NSApp.publisher(for: \.currentEvent)
.filter { event in event?.type == .scrollWheel }
.throttle(for: .milliseconds(200),
scheduler: DispatchQueue.main,
latest: true)
.sink { [weak vm] event in
vm?.goBackOrForwardBy(delta: Int(event?.deltaY ?? 0))
}
.store(in: &subs)
}

@State var subs = Set<AnyCancellable>() // Cancel onDisappear

关于xcode - SwiftUI:如何在水平 ScrollView 中监听鼠标滚轮滚动事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64530822/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com