将可拖动的 NSView 与 SwiftUI 组件相结合的问题
Problem combining a draggable NSView with SwiftUI components
我有一个使用 Cocoa:
编写的 NSView-class
import Cocoa
import SwiftUI
final class EntityViewImpl: NSViewRepresentable {
func makeNSView(context: NSViewRepresentableContext<EntityViewImpl>) -> EntityView {
return EntityView(frame: NSRect(x: 0, y: 0, width: 100, height: 200))
}
func updateNSView(_ nsView: EntityView, context: NSViewRepresentableContext<EntityViewImpl>) {
// do nothing
}
}
class EntityView: NSView {
var oldMousePosition: NSPoint = .zero
var oldFrameOrigin: NSPoint = .zero
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
NSColor.white.setFill()
dirtyRect.fill()
}
override func mouseDown(with event: NSEvent) {
self.oldFrameOrigin = self.frame.origin
self.oldMousePosition = event.locationInWindow
}
override func mouseDragged(with event: NSEvent) {
let pointInSuperview = event.locationInWindow
self.frame.origin = NSPoint(x: oldFrameOrigin.x + (pointInSuperview.x - oldMousePosition.x),
y: oldFrameOrigin.y + (pointInSuperview.y - oldMousePosition.y))
}
}
我想在 SwiftUI View-body 中使用这个 class,例如:
struct ContentView: View {
var body: some View {
Group {
EntityViewImpl()
.frame(width: 100, height: 100)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
这很好用,我也可以在 EntityView
周围拖动。但是,我只能 "grab" 它在它的原始框架内。如果我将它拖到边界之外,鼠标事件将不再在原始框架之外的视图部分触发。我是否必须以某种方式 "tell" NSView 移动的 ContentView?
其实如果你用的是SwiftUI,你需要移动EntityView的superview,像这样:
override func mouseDown(with event: NSEvent) {
self.oldFrameOrigin = self.superview!.frame.origin
self.oldMousePosition = self.superview!.convert(event.locationInWindow, from: self)
}
override func mouseDragged(with event: NSEvent) {
let pointInSuperview = self.superview!.convert(event.locationInWindow, from: self)
self.superview!.frame.origin = NSPoint(x: oldFrameOrigin.x + (pointInSuperview.x - oldMousePosition.x),
y: oldFrameOrigin.y + (-pointInSuperview.y + oldMousePosition.y))
}
我有一个使用 Cocoa:
编写的 NSView-classimport Cocoa
import SwiftUI
final class EntityViewImpl: NSViewRepresentable {
func makeNSView(context: NSViewRepresentableContext<EntityViewImpl>) -> EntityView {
return EntityView(frame: NSRect(x: 0, y: 0, width: 100, height: 200))
}
func updateNSView(_ nsView: EntityView, context: NSViewRepresentableContext<EntityViewImpl>) {
// do nothing
}
}
class EntityView: NSView {
var oldMousePosition: NSPoint = .zero
var oldFrameOrigin: NSPoint = .zero
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
NSColor.white.setFill()
dirtyRect.fill()
}
override func mouseDown(with event: NSEvent) {
self.oldFrameOrigin = self.frame.origin
self.oldMousePosition = event.locationInWindow
}
override func mouseDragged(with event: NSEvent) {
let pointInSuperview = event.locationInWindow
self.frame.origin = NSPoint(x: oldFrameOrigin.x + (pointInSuperview.x - oldMousePosition.x),
y: oldFrameOrigin.y + (pointInSuperview.y - oldMousePosition.y))
}
}
我想在 SwiftUI View-body 中使用这个 class,例如:
struct ContentView: View {
var body: some View {
Group {
EntityViewImpl()
.frame(width: 100, height: 100)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
这很好用,我也可以在 EntityView
周围拖动。但是,我只能 "grab" 它在它的原始框架内。如果我将它拖到边界之外,鼠标事件将不再在原始框架之外的视图部分触发。我是否必须以某种方式 "tell" NSView 移动的 ContentView?
其实如果你用的是SwiftUI,你需要移动EntityView的superview,像这样:
override func mouseDown(with event: NSEvent) {
self.oldFrameOrigin = self.superview!.frame.origin
self.oldMousePosition = self.superview!.convert(event.locationInWindow, from: self)
}
override func mouseDragged(with event: NSEvent) {
let pointInSuperview = self.superview!.convert(event.locationInWindow, from: self)
self.superview!.frame.origin = NSPoint(x: oldFrameOrigin.x + (pointInSuperview.x - oldMousePosition.x),
y: oldFrameOrigin.y + (-pointInSuperview.y + oldMousePosition.y))
}