在层支持的NSView中更改了CALayer的锚点

时间:2018-03-09 11:13:31

标签: macos cocoa core-animation calayer nsview

我试图通过设置背衬层的变换动画,在支持图层的NSView上运行缩放动画。我遇到的问题是,动画放大到左下角而不是视图的中心。我发现这是因为NSView将其支持层的锚点设置为(0,0),即使我将其更改为其他值也是如此。这篇post讨论了类似的问题。

我知道要解决这个问题,我可以将视图作为图层托管视图。但是,我想使用自动布局,这就是为什么这不是一个真正的选择。

有没有人知道绕过这种行为的另一种方法,并将视图的背景层的锚点保持在(0.5,0.5)?我在上面链接的帖子中摘录了苹果的文档,讨论了NSView封面方法。什么样的覆盖方法可以用于锚点?

非常感谢!

1 个答案:

答案 0 :(得分:0)

诀窍是覆盖支持层并传递选择的锚点(例如,能够从左上角缩放)。这是我使用的:

extension CGPoint {
  static let topLeftAnchor: Self = .init(x: 0.0, y: 1.0)
  static let bottomLeftAnchor: Self = .init(x: 0.0, y: 0.0)
  static let topRightAnchor: Self = .init(x: 1.0, y: 1.0)
  static let bottomRightAnchor: Self = .init(x: 1.0, y: 0.0)
  static let centerAnchor: Self = .init(x: 0.5, y: 0.5)
}

class AnchoredLayer: CALayer {
  public var customAnchorPoint = CGPoint.topLeftAnchor
  
  override var anchorPoint: CGPoint {
    get { customAnchorPoint }
    set { super.anchorPoint = customAnchorPoint }
  }
}

class AnchoredView: NSView {
  required convenience init(anchoredTo point: CGPoint) {
    self.init(frame: .zero)
    self.wantsLayer = true
    self.anchorPoint = point
  }
  
  public override func makeBackingLayer() -> CALayer {
    let roundedLayer = AnchoredLayer()
    return roundedLayer
  }
  
  public var anchorPoint: CGPoint {
    get { (layer as! AnchoredLayer).customAnchorPoint }
    set { (layer as! AnchoredLayer).customAnchorPoint = newValue }
  }
}

然后照常使用AnchoredView

    let myView = AnchoredView(anchoredTo: .topLeftAnchor)

    // Create the scale animation
    let transformScaleXyAnimation = CASpringAnimation()
    transformScaleXyAnimation.fillMode = .forwards
    transformScaleXyAnimation.keyPath = "transform.scale.xy"
    transformScaleXyAnimation.toValue = 1
    transformScaleXyAnimation.fromValue = 0.8
    transformScaleXyAnimation.stiffness = 300
    transformScaleXyAnimation.damping = 55
    transformScaleXyAnimation.mass = 0.8
    transformScaleXyAnimation.initialVelocity = 4
    transformScaleXyAnimation.duration = transformScaleXyAnimation.settlingDuration

    myView.layer?.add(transformScaleXyAnimation, forKey: "transformScaleXyAnimation")
...