核心动画:在10.8上设置anchorPoint以围绕其中心旋转图层

10

注意:本问题针对的是Mac OS X上的Cocoa应用程序,而不是iOS。

我有一个基于图层的NSButton(NSView子类)。我想要使用Core Animation旋转该按钮。我正在使用以下代码来实现:

CABasicAnimation *a = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
a.fromValue = [NSNumber numberWithFloat:0];
a.toValue = [NSNumber numberWithFloat:-M_PI*2];
[_refreshButton.layer setAnchorPoint:CGPointMake(0.5, 0.5)];
a.duration = 1.8; // seconds
a.repeatCount = HUGE_VAL;
[_refreshButton.layer addAnimation:a forKey:nil];

这段代码能够正常运行,但是当它执行时,图层会向下和向左跳动,导致其中心点位于NSView的原点(0,0)即左下角。虽然图层会围绕其中心旋转,但显然向左下角跳跃是不可接受的。

因此,经过大量阅读,我在10.8 API发布说明中找到了以下这行代码:

On 10.8, AppKit will control the following properties on a CALayer 
(both when "layer-hosted" or "layer-backed"): geometryFlipped, bounds, 
frame (implied), position, anchorPoint, transform, shadow*, hidden, 
filters, and compositingFilter. Use the appropriate NSView cover methods 
to change these properties.
这意味着AppKit在上面的代码中“忽略”了我的-setAnchorPoint调用,而是将该锚点设置为NSView的原点(0,0)。
我的问题是:我该怎么解决?有什么“适当的NSView覆盖方法”可以为图层设置anchorPoint(我在NSView上找不到这样的方法)。归根结底,我只想让我的按钮无限制地围绕其中心点旋转。
2个回答

17

我在NSView上没有看到任何直接“覆盖”anchorPoint的方法。

除了你引用的内容之外,我在10.8版本说明中还看到了这个:

anchorPoint也始终设置为(0,0),...

anchorPoint控制图层中位于超级图层坐标系中的position点。 NSViewself.layer.anchorPoint设置为(0,0),这意味着图层的左下角位于self.layer.position

当您将anchorPoint设置为(0.5,0.5)时,这意味着图层的中心应该位于图层的position。由于您没有修改position,因此这会导致图层向下和向左移动,就像您所看到的那样。

您需要计算出在其anchorPoint为(0.5,0.5)时要使图层具有的position,如下:

CGRect frame = _refreshButton.layer.frame;
CGPoint center = CGPointMake(CGRectGetMidX(frame), CGRectGetMidY(frame));
_refreshButton.layer.position = center;
_refreshButton.layer.anchorPoint = CGPointMake(0.5, 0.5);

太好了!你知道吗,我看到了position属性,但是因为上面的注释说AppKit将控制它,所以没有尝试过。感谢你提供的解决方案! - Bryan
任何想法为什么旋转 M_PI/2 第一次会逆时针旋转,之后会顺时针旋转? - greg
我需要看看你的代码。你应该发布自己的问题。 - rob mayoff
这里是链接:http://stackoverflow.com/questions/24623725/cabasicanimation-rotating-wrong-direction-first-time - greg

0

我在Swift中遇到了与@Bryan完全相同的问题:对象在动画期间会跳离其原始位置。这是用于macOS脉冲NSButton的代码:

  let frame : CGRect = startButton.layer!.frame
  let center : CGPoint = CGPoint(x: frame.midX, y: frame.midY)
  startButton.layer?.position = center;
  startButton.layer?.anchorPoint = CGPoint(x: 0.5, y: 0.5)
        
  let pulse = CASpringAnimation(keyPath: "transform.scale")
  pulse.duration = 0.2
  pulse.fromValue = 0.95
  pulse.toValue = 1.0
  pulse.autoreverses = true
  pulse.repeatCount = 10
  pulse.initialVelocity = 0.5
  pulse.damping = 1.0
        
  startButton.layer?.add(pulse, forKey: "pulse")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接