12
votes

Trying to understand the relationship between UIView and CALayer. I read Apple documentation but it doesn't describe in detail the relationship between the two.

  1. Why is it that when I add the background image to view "customViewController.view", I get the unwanted black color of the image.

  2. And when I add the background image to the layer "customViewController.view.layer", the black area of the image is gone (which is what I wanted), but the background image is flipped upside down. Why is that?

  3. If I were to add labels/views/buttons/etc. to the view, will the layer's background image block them because CAlayer is backed by UIView?

  4. When you set the background color of a UIView does it automatically set the background color of the associated layer?

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        customViewController = [[CustomViewController alloc] init];
        customViewController.view.frame = CGRectMake(213, 300, 355, 315);
    
        customViewController.view.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:@"login_background.png"]];
        //  customViewController.view.layer.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:@"login_background.png"]].CGColor;
    
        [self.view addSubview:customViewController.view];
    }
    

Background image in view:

background in view

- (void)viewDidLoad
{
    [super viewDidLoad];
    customViewController = [[CustomViewController alloc] init];
    customViewController.view.frame = CGRectMake(213, 300, 355, 315);

//  customViewController.view.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:@"login_background.png"]];
    customViewController.view.layer.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:@"login_background.png"]].CGColor;

    [self.view addSubview:customViewController.view];
}

Background image in view.layer:

background image in layer

1

1 Answers

10
votes
  1. UIView as created opaque by default. When you set the backgroundColor to a pattern with transparency it is choosing black as the background color. You can set customViewController.view.opaque = NO; to allow the background of the view behind yours to show through.

  2. When you set the backgroundColor of the layer to a pattern with transparency you are bypassing the UIView logic, so the opaqueness of the view is ignored; so also is the the UIView's transform. CoreGraphics and friends use a coordinate system where the positive y-axis points upwards. UIKit flips this coordinate system. This is why the image appears upside down.

  3. If you add labels/views/buttons/etc. the will appear correctly on top of the layer's background pattern.

  4. When you set the view's background color it appears as if the layer's background color is indeed set. (I have not seen this documented anywhere).

Essentially the UIKit's UIView stuff is a high-level interface which ends up rendered onto layers.

Hope this helps.

EDIT 5/7/2011

You can get the image to show the right way up by flipping the layer's coordinate system BUT you shouldn't do this to view.layer; UIKit doesn't expect you to mess with this layer, so if your flip its coordinate system any UIKit drawing will be flipped; you need to use a sublayer.

So your code would look like this:

- (void)viewDidLoad
{
    [super viewDidLoad];
    customViewController = [[CustomViewController alloc] init];
    customViewController.view.frame = CGRectMake(213, 300, 355, 315);

    CALayer* l = [CALayer layer];
    l.frame = customViewController.bounds;
    CGAffineTransform t = CGAffineTransformMake(1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
    l.affineTransform = t;
    l.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage
                             imageNamed:@"login_background.png"]].CGColor;
    [customViewController.view.layer addSublayer:l];

    [self.view addSubview:customViewController.view];
}

Note: normally when you flip coordinates you include the height. For layers you don't need to do this. I haven't dug into why this is so.

As you can see there is a lot more code involved here and there is no real advantage to doing it this way. I really recommend you stick to the UIKit approach. I only posted the code in response to your curiosity.