Как обновить положение слоя NSView и точку привязки для преобразования одновременно с рамкой NSView для событий мыши - PullRequest
0 голосов
/ 10 июня 2018

В настоящее время я пытаюсь реализовать некоторые пользовательские NSView, которые будут анимироваться определенными событиями в приложении MacOS.Элементы управления расположены вдоль линий ползунка, которые вы найдете в плагине AudioUnit.

На вопрос об анимации был дан ответ в на этот вопрос .

В чем я не уверенэто то, как изменить положение CALayer вида и опорную точку для поворота и обновить его кадр для событий мыши.

В качестве базового примера я хочу нарисовать квадрат, создав NSView и установив его цвет фона.Затем я хочу анимировать вращение вида, как и предыдущая ссылка, по событию mouseDown.

При следующей настройке вид перемещается в центр окна, его точка привязки изменяется таким образом, чтовид вращается вокруг него, а не вокруг источника window.contentView!.Однако перемещение view.layer.position и установка view.layer!.anchorPoint = CGPoint(x: 0.5,y: 0.5) также не перемещают кадр, который будет обнаруживать события.

@IBOutlet weak var window: NSWindow!

func applicationDidFinishLaunching(_ aNotification: Notification)
{
    let view = customView(frame: NSRect(x: 0, y: 0, width: 50, height: 50))
    window.contentView!.wantsLayer = true
    view.wantsLayer = true
    view.layer?.backgroundColor = NSColor.blue.cgColor
    window.contentView?.addSubview(view)

    let containerFrame = window.contentView!.frame
    let center = CGPoint(x: containerFrame.midX, y: containerFrame.midY)
    view.layer?.position = center
    view.layer?.anchorPoint = CGPoint(x: 0.5,y: 0.5)
}

В этом случае customView - это просто NSView с анимацией вращения из предыдущей ссылкивыполняется на mouseDown

override func mouseDown(with event: NSEvent)
    {
        let timeToRotate = 1
        let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation")
        rotateAnimation.fromValue = 0.0
        rotateAnimation.toValue = angle
        rotateAnimation.duration = timeToRotate
        rotateAnimation.repeatCount = .infinity
        self.layer?.add(rotateAnimation, forKey: nil)
    }

Перемещение кадра с помощью установки view.frame = view.layer.frame приводит к вращению вида вокруг одного из его углов.Итак, вместо этого я изменил view.setFrameOrigin()

@IBOutlet weak var window: NSWindow!

func applicationDidFinishLaunching(_ aNotification: Notification)
{
    let view = customView(frame: NSRect(x: 0, y: 0, width: 50, height: 50))
    window.contentView!.wantsLayer = true
    view.wantsLayer = true
    view.layer?.backgroundColor = NSColor.blue.cgColor
    window.contentView?.addSubview(view)

    let containerFrame = window.contentView!.frame
    let center = CGPoint(x: containerFrame.midX, y: containerFrame.midY)
    let offsetFrameOrigin = CGPoint(x: center.x - view.bounds.width/2,
                                    y: center.y - view.bounds.height/2)
    view.setFrameOrigin(offsetFrameOrigin)
    view.layer?.position = center
    view.layer?.anchorPoint = CGPoint(x: 0.5,y: 0.5)
}

Установка начала координат view.frame со смещением от центра добивается того, чего я хочу, но я не могу не чувствовать, что это немного «хакерски» ичто я могу подойти к этому неправильно.Тем более, что любое дальнейшее изменение на view.layer или view.frame приведет либо к некорректной анимации, либо к обнаружению событий вне нарисованного.

Как я могу изменить NSView.layer так, чтобы он вращался вокруг своего центраодновременно с настройкой NSView.frame, чтобы события мыши обнаруживались в правильной области?

Кроме того, является ли изменение NSView.layer.anchorPoint правильным способом настройки его вращения вокруг его центра?

1 Ответ

0 голосов
/ 17 июня 2018

Я думаю, что я нахожусь в той же позиции, что и вы.К счастью, я наткнулся на суть , которая расширяет NSView с помощью функции setAnchorPoint , которая выполняет всю работу за меня (поддерживая привязку слоя в синхронизации с основным кадром).

Есть вилка для этой цели для Swift 4 .Вот сам код:

extension NSView
{
    func setAnchorPoint (anchorPoint:CGPoint)
    {
        if let layer = self.layer
        {
            var newPoint = CGPoint(x: self.bounds.size.width * anchorPoint.x, y: self.bounds.size.height * anchorPoint.y)
            var oldPoint = CGPoint(x: self.bounds.size.width * layer.anchorPoint.x, y: self.bounds.size.height * layer.anchorPoint.y)

            newPoint = newPoint.applying(layer.affineTransform())
            oldPoint = oldPoint.applying(layer.affineTransform())

            var position = layer.position

            position.x -= oldPoint.x
            position.x += newPoint.x

            position.y -= oldPoint.y
            position.y += newPoint.y

            layer.position = position
            layer.anchorPoint = anchorPoint
        }
    }
}

Затем вы можете использовать его следующим образом на NSView напрямую (т.е. не на его слое):

func applicationDidFinishLaunching(_ aNotification: Notification)
{
    // ... //
    let view = customView(frame: NSRect(x: 0, y: 0, width: 50, height: 50))
    view.wantsLayer = true
    view.setAnchorPoint(anchorPoint: CGPoint(x: 0.5, y: 0.5))
    // ... //
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...