Changing frame of UIView's CALayer (self.view.layer.frame = ...) appears to have no effect

15,131

Solution 1

Actually, the previous answer (you can't set uiview.layer.frame as it always fills the uiview) is close, but not quite complete. After reading the answer, I registered for the original site and to comment that the tutorial had issues. In doing so, I found that there were already comments that I hadn't seen in my first pass that addressed this. Using those, I started doing some testing.

The bottom line, if you move the self.view.layer.frame setting code from viewDidLoad to viewWillAppear, it works fine. That means that you can change the frame of the root layer of a view. However, if you do it in viewDidLoad it will be undone later.

However, the previous answer is still pretty close. I NSLog'ed the frame of the root layer and the frame of the view. Changing the root layer frame changes the view frame. So, the answer that the view.layer.frame always fills the view.frame is correct. However, setting the layer frame resets the view frame to match. (I'm guessing that uiview.frame property simply returns uiview.layer.frame...)

So, at some point in time between 2010 and today, something in the environment changed. Specifically, after viewDidLoad and before viewWillAppear the uiview/layer frame appears to be reset to the nib specified value. This overrides any changes in viewDidLoad. Changes made in viewWillAppear appear to stick.

Robin's answer got me on the right track, but I wanted to spell out the full answer.

Solution 2

The tutorial is wrong. Setting the frame of the view's main layer has no effect. The main layer is 'special' and will always fill the view's bounds. What you need to do is create a sublayer of the main layer like this:

- (void)viewDidLoad
{
    [super viewDidLoad];

    CALayer *newLayer = [[CALayer alloc] init];

    newLayer.backgroundColor = [UIColor orangeColor].CGColor;
    newLayer.cornerRadius = 20.0;
    newLayer.frame = CGRectMake(100.0f, 100.0f, 200.0f, 200.0f);

    [self.view.layer addSublayer:newLayer];

    [newLayer release]; // Assuming you're not using ARC
}

Also, in your code a layer with width 20pt and height 20pt is too small to have rounded corners of 30pt anyway.

Share:
15,131
pmeyer
Author by

pmeyer

Updated on August 09, 2022

Comments

  • pmeyer
    pmeyer over 1 year

    I'm sure I'm missing something basic here. I'm trying out the CALayers 'hello world' code from:

    http://www.raywenderlich.com/2502/introduction-to-calayers-tutorial

    Doing the very first example. New single view project in xcode 4.2. No change to the nib/storyboard. Import QuartzCore. Add the following code to ViewDidLoad in the ViewController.m:

    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        self.view.layer.backgroundColor = [UIColor blueColor].CGColor;
        self.view.layer.cornerRadius = 30.0;    
        self.view.layer.frame = CGRectMake(20, 20, 20, 20);
    }
    

    I run this (ipad 2 or ipad simulator) and get a full screen blue rectangle with rounded corners. What I hoped to get was a 20x20 blue rectangle offset by 20/20.

    I'm clearly getting control over the views layer (as shown by the color and rounded corners). However, adjusting the frame seems to have no impact. I've NSLog'ed the frame before/after setting it, and it has changed. Is the frame of the root layer locked to the uiview frame?

    I don't have a strong reason to change the views layers frame, I'm just trying to reason through what is going on. Hopefully this is an easy question...

    Thanks!

    Paul