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)?