CALayer 帧值即使在从超级层中移除后也会导致动画

Posted

技术标签:

【中文标题】CALayer 帧值即使在从超级层中移除后也会导致动画【英文标题】:CALayer frame value causing animation even after removal from superlayer 【发布时间】:2013-02-24 16:31:26 【问题描述】:

进入 CALayer 世界:

我正在创建一个无论设备方向如何都需要保持在视图中间的层。有人可以告诉我为什么我的图层在从旧位置旋转后会动画,即使我将它从超级图层中移除?我知道 frame 和 borderWidth 属性是可动画的,但是即使从 superLayer 中删除它们也可以动画吗?

如果从 superLayer 中移除并不会重置图层属性,因为图层对象尚未释放(好吧,我可以理解),我如何模仿新显示图层的行为,以便边框不会像它一样显示旋转后从旧位置移动。

我创建了这个示例项目 - 如果您愿意,可以剪切和粘贴。您只需要链接石英核心库。

#import "ViewController.h"
#import <QuartzCore/QuartzCore.h>

@interface ViewController ()
@property (nonatomic,strong) CALayer *layerThatKeepAnimating;
@end

@implementation ViewController

-(CALayer*) layerThatKeepAnimating

  if(!_layerThatKeepAnimating)
  
    _layerThatKeepAnimating=[CALayer layer];
    _layerThatKeepAnimating.borderWidth=2;
  
return _layerThatKeepAnimating;



-(void) viewDidAppear:(BOOL)animate
    
self.layerThatKeepAnimating.frame=CGRectMake(self.view.bounds.size.width/2-50,self.view.bounds.size.height/2-50, 100, 100);
  [self.view.layer addSublayer:self.layerThatKeepAnimating];



-(void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration

  [self.layerThatKeepAnimating removeFromSuperlayer];



-(void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation

  self.layerThatKeepAnimating.frame=CGRectMake(self.view.bounds.size.width/2-50,self.view.bounds.size.height/2-50, 100, 100);
  [self.view.layer addSublayer:self.layerThatKeepAnimating];


@end

【问题讨论】:

Disable animation when moving CALayers的可能重复 该链接中接受的答案(尽管我会使用 setDisablesActions)将满足您的需求。 @jrturton,这不是重复的。另一个链接上的两个答案和您的答案都与 CATransaction 相关。我这里没用。 我的意思是,您应该使用 CATransaction 来覆盖隐式动画。 @jrturton,感谢您的指导。在我看来,当我们只是谈论框架时,CATransaction 是矫枉过正的。请看下文。看起来 viewWillLayoutSubviews 在某种程度上与 setDisablesActions 一样,至少对于我正在使用的属性。 【参考方案1】:

虽然听起来很奇怪,但答案是将代码移入

willRotateToInterfaceOrientation 到 viewWillLayoutSubviews

-(void) viewWillLayoutSubviews

    self.layerThatKeepAnimating.frame=CGRectMake(self.view.bounds.size.width/2-50,self.view.bounds.size.height/2-50, 100, 100);
    [self.view.layer addSublayer:self.layerThatKeepAnimating];

看起来这里的任何图层“重绘”都是在没有动画的情况下发生的,即使图层属性是可动画的。

【讨论】:

【参考方案2】:

问题不是你想的那样;当您从超级视图中删除该层时,它实际上并没有被取消,因为您保留了对它的强引用。您的代码没有在 getter 中输入 if 语句来创建新层,因为它在第一次之后永远不会为零:

if(!_layerThatKeepAnimating)
  
    _layerThatKeepAnimating=[CALayer layer];
    _layerThatKeepAnimating.borderWidth=2;
  

所以要么将你在 vc 中对 layer 的引用改为weak:

@property (nonatomic, weak) CALayer * layerThatKeepAnimating;

或通过以下方式显式删除它:

-(void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration

  [self.layerThatKeepAnimating removeFromSuperlayer];
  self.layerThatKeepAnimating = nil;

我建议您使用第一个选项,因为当您向视图添加层(或子视图)时,您已经获得了一个强有力的参考。这就是为什么总是建议这样做:

@property (weak, nonatomic) IBOutlet UIView *view;

但不是(强的、非原子的)。

【讨论】:

【参考方案3】:
[self.sublayerToRemove removeFromSuperlayer];
self.sublayerToRemove = nil;

【讨论】:

以上是关于CALayer 帧值即使在从超级层中移除后也会导致动画的主要内容,如果未能解决你的问题,请参考以下文章

modalViewController 从 superview 中移除后 UIView 消失

SKSpriteNode 从场景中移除后如何停止音频(Swift)?

UIView 即使在开始从超级视图中删除后也会重新出现

即使在手机被擦除后也能跟踪 iOS 设备

位于关键帧值中间的 CALayer 的 CAKeyframeAnimation?

在 KineticJS 中移除舞台