0

Into the CALayer world:

I am creating a layer that needs to remain in middle of view regardless of device orientation. Can someone tell me why does my layer animates after rotation from the old position even though I removed it from superlayer? I understand that the frame and borderWidth properties are animatable but are they animatable even after removal from superLayer?

And if removal from superLayer does not reset the layer properties because the layer object has not been released (ok I can understand that), how do I mimic the behavior of a newly displayed layer so that the border does not shows like it is moving from an old position after rotation.

I created this sample project - cut and paste if you wish. You will just need to link the quartz core library.

#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
Khaled Barazi
  • 8,681
  • 6
  • 42
  • 62
  • possible duplicate of [Disable animation when moving CALayers](http://stackoverflow.com/questions/2930166/disable-animation-when-moving-calayers) – jrturton Feb 24 '13 at 16:39
  • The accepted answer in that link (though I'd use setDisablesActions) will do what you need. – jrturton Feb 24 '13 at 16:40
  • @jrturton, this is not a duplicate. Both answers on the other link and yours pertain to CATransaction. I am not using it here. – Khaled Barazi Feb 24 '13 at 16:44
  • My point is, you _should_ use a CATransaction to override the implicit animation. – jrturton Feb 24 '13 at 16:46
  • @jrturton, thanks for the direction. It seems to me that CATransaction is overkill when we are just talking about the frame. Please see below. It looks like viewWillLayoutSubviews somehow does the same as setDisablesActions at least for the properties I am using. – Khaled Barazi Feb 24 '13 at 16:53
  • CATransaction is happening in the background anyway. It's not overkill, you're just overriding the default. – jrturton Feb 24 '13 at 17:08

3 Answers3

0

As odd as this sounds, the answer is to move code in

willRotateToInterfaceOrientation to 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];
}

It looks like any layer "redrawing" here happens without animation, even if layer properties are animatable.

Khaled Barazi
  • 8,681
  • 6
  • 42
  • 62
0

Well the problem is not what you think; when you remove that layer from the superview it is not actually nillified because you are retaining a strong reference to it. Your code doesn't enter the if statement in the getter for creating a fresh layer, because it is never nil after the first time:

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

So either change your reference to layer in vc to weak:

@property (nonatomic, weak) CALayer * layerThatKeepAnimating;

Or delete it explicitly by:

-(void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
  [self.layerThatKeepAnimating removeFromSuperlayer];
  self.layerThatKeepAnimating = nil;
}

I will suggest you to use the first option because as you add layers (or subviews) to views you already earn one strong reference. That's why it is always recommended do it like this:

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

but not (strong, nonatomic).

guenis
  • 2,520
  • 2
  • 25
  • 37
0
[self.sublayerToRemove removeFromSuperlayer];
self.sublayerToRemove = nil;
jonypz
  • 1,515
  • 1
  • 20
  • 35