Как переместить NSImageView внутри NSView в Какао?
В моем приложении Mac OS мне нужна функциональность, чтобы иметь возможность перемещать NSImageView внутри NSView после того, как событие mouseDown (инициированное пользователем) происходит в этом NSImageView. Когда пользователь запускает событие мыши Up, это представление должно переместиться в направлении последнего события mouseDrag и остаться там. Во время перемещения я хочу, чтобы NSImageView был виден на экране (он должен двигаться вместе с курсором мыши).
Я прочитал руководство Apple по обработке событий мыши, https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/EventOverview/HandlingMouseEvents/HandlingMouseEvents.html Также я скачал этот пример кода: https://developer.apple.com/library/content/samplecode/DragItemAround/Introduction/Intro.html
Обе ссылки содержат код в Objective C. Код для DragItemAround устарел. Я пытался найти решения на GitHub и других потоках Stackru, но не нашел никаких рабочих решений.
Был бы рад услышать ответы на этот вопрос. Я использую Swift 3.
Я создал собственный MovableImageView, который является подклассом NSImageView с этим кодом:
import Cocoa
class MovableImageView: NSImageView {
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
// Drawing code here.
// setup the starting location of the
// draggable item
}
override func mouseDown(with event: NSEvent) {
Swift.print("mouseDown")
//let window = self.window!
//let startingPoint = event.locationInWindow
}
override func mouseDragged(with event: NSEvent) {
Swift.print("mouseDragged")
self.backgroundColor = NSColor.black
}
override func mouseUp(with event: NSEvent) {
Swift.print("mouseUp")
}
}
После этого в Интерфейсном Разработчике я установил этот класс в NSImageView. Я также установил ограничения в Интерфейсном Разработчике для этого NSImageView.
Теперь я пытаюсь выяснить, как переместить NSImageView внутри NSView? (Swift 3, XCode 8)
3 ответа
Вам нужно сохранить точку mouseDown и использовать ее для смещения позже. Пожалуйста, проверьте следующий код:
class MovableImageView: NSImageView {
var firstMouseDownPoint: NSPoint = NSZeroPoint
init() {
super.init(frame: NSZeroRect)
self.wantsLayer = true
self.layer?.backgroundColor = NSColor.red.cgColor
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
// Drawing code here.
}
override func mouseDown(with event: NSEvent) {
Swift.print("mouseDown")
firstMouseDownPoint = (self.window?.contentView?.convert(event.locationInWindow, to: self))!
}
override func mouseDragged(with event: NSEvent) {
Swift.print("mouseDragged")
let newPoint = (self.window?.contentView?.convert(event.locationInWindow, to: self))!
let offset = NSPoint(x: newPoint.x - firstMouseDownPoint.x, y: newPoint.y - firstMouseDownPoint.y)
let origin = self.frame.origin
let size = self.frame.size
self.frame = NSRect(x: origin.x + offset.x, y: origin.y + offset.y, width: size.width, height: size.height)
}
override func mouseUp(with event: NSEvent) {
Swift.print("mouseUp")
}
}
В родительском представлении просто добавьте этот MovableImageView как подпредставление следующим образом:
let view = MovableImageView()
view.frame = NSRect(x: 0, y: 0, width: 100, height: 100)
self.view.addSubview(view) //Self is your parent view
Ограниченная версия ответа @brianLikeApple:
class MovableImageView: NSImageView {
var firstMouseDownPoint: NSPoint = NSZeroPoint
var xConstraint: NSLayoutConstraint!
var yContstraint: NSLayoutConstraint!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.wantsLayer = true
self.layer?.backgroundColor = NSColor.red.cgColor
}
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
// Drawing code here.
}
override func mouseDown(with event: NSEvent) {
Swift.print("mouseDown")
firstMouseDownPoint = (self.window?.contentView?.convert(event.locationInWindow, to: self))!
}
override func mouseDragged(with event: NSEvent) {
Swift.print("mouseDragged")
let newPoint = (self.window?.contentView?.convert(event.locationInWindow, to: self))!
let offset = NSPoint(x: newPoint.x - firstMouseDownPoint.x, y: newPoint.y - firstMouseDownPoint.y)
let origin = self.frame.origin
let size = self.frame.size
yContstraint.constant = (self.superview?.frame.height)! - origin.y - offset.y - size.height
xConstraint.constant = origin.x + offset.x
}
override func mouseUp(with event: NSEvent) {
Swift.print("mouseUp")
}
Вот NSView, который вы можете перетащить. Он использует ограничения точно так же, как ответ @ExeRhythm.
import AppKit
class DraggableNSView: NSView {
var down: NSPoint = NSZeroPoint
@IBOutlet var across: NSLayoutConstraint!
@IBOutlet var up: NSLayoutConstraint!
override func mouseDown(with e: NSEvent) {
down = window?.contentView?.convert(e.locationInWindow, to: self) ?? NSZeroPoint
}
override func mouseDragged(with e: NSEvent) {
guard let m = window?.contentView?.convert(e.locationInWindow, to: self) else { return }
let p = frame.origin + (m - down)
across.constant = p.x
up.constant = p.y
}
}
Не забывайте, что вы должны подключить
across
а также
up
ограничения в раскадровке!
Примечание. Если вы предпочитаете ограничение «вниз», а не «вверх», это:
// if you prefer a "down" constraint:
down.constant = (superview?.frame.height)! - p.y - frame.size.height
Как всегда, добавьте эти две функции в свой проект,
func -(lhs: CGPoint, rhs: CGPoint) -> CGPoint {
return CGPoint(x: lhs.x - rhs.x, y: lhs.y - rhs.y)
}
func +(lhs: CGPoint, rhs: CGPoint) -> CGPoint {
return CGPoint(x: lhs.x + rhs.x, y: lhs.y + rhs.y)
}
Обратите внимание, что вы, конечно, можете сделать это для любого подкласса NSView, такого как NSImageView:
class DraggableNSImageView: NSView {
... same