【问题标题】:CALayer frame value causing animation even after removal from superlayerCALayer 帧值即使在从超级层中移除后也会导致动画
【发布时间】: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

【问题讨论】:

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

标签: ios uiview uiviewcontroller calayer quartz-core


【解决方案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;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-20
        • 2010-09-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多