Question

I am trying to load a profile image for an app, but I want to add a white border to it and make it circular before I display it. In order to do that I set the image property on the UIImageView and then prepare the image by setting the appropriate corner radius, masking it to the bounds and then adding a white border sublayer. Originally, I was loading the image in over the internet asynchronously and everything worked fine because the image appeared after the view had appeared. However, when I cached the image and tried to prepare it before the imageView was shown on screen I couldn't get the border sublayer to display. It still masked properly, just no border. The code that I am using to prepare the image is below.

- (void)prepareProfileImage
{
    CALayer *imageLayer = self.profileImageView.layer;
    imageLayer.borderColor = [UIColor whiteColor].CGColor;
    imageLayer.allowsEdgeAntialiasing = NO;
    [imageLayer setCornerRadius:PROFILE_IMAGE_DIAMETER/2.0];
    [imageLayer setMasksToBounds:YES];

    CALayer *borderLayer = [CALayer layer];
    CGRect borderFrame = CGRectMake(-1.0, -1.0, (self.profileImageView.frame.size.width+2.0), (self.profileImageView.frame.size.height+2.0));
    [borderLayer setBackgroundColor:[[UIColor whiteColor] CGColor]];
    [borderLayer setFrame:borderFrame];
    [borderLayer setCornerRadius:PROFILE_IMAGE_DIAMETER/2.0];
    [borderLayer setBorderWidth:PROFILE_IMAGE_BORDER_WIDTH+1.0];
    [borderLayer setBorderColor:[UIColor whiteColor].CGColor];

    [imageLayer addSublayer:borderLayer];
}

This method works fine as long as it's called after viewDidLoad, but will not add the border layer if called before viewDidLoad. I have confirmed that self.profileImageView has been allocated at the time of this method call, but I only get the circular image, no border.

Is there something that I am misunderstanding about CALayers? Should it matter when I add the layer as a sublayer?

The reason I am not using the border property directly on the image layer is that it leaves a tiny sliver of image around the outside that is displeasing.

Was it helpful?

Solution

I have found the answer! The problem was that I want setting the frame of the border layer using the profileImageView frame, but because I am using autolayout that property is not set until after the view is displayed on screen.

I ended up doing:

 /*! This function adds a border layer to the profile image view. */
- (void)addBorderLayerToProfileImageView {
    CALayer *borderLayer = [CALayer layer];
    CGRect borderFrame = CGRectMake(-1.0, -1.0, (PROFILE_IMAGE_DIAMETER+2.0), (PROFILE_IMAGE_DIAMETER+2.0));
    [borderLayer setBackgroundColor:[[UIColor clearColor] CGColor]];
    [borderLayer setFrame:borderFrame];
    [borderLayer setCornerRadius:PROFILE_IMAGE_DIAMETER/2.0];
    [borderLayer setBorderWidth:PROFILE_IMAGE_BORDER_WIDTH+1.0];
    [borderLayer setBorderColor:[UIColor whiteColor].CGColor];
    [self.profileImageView.layer addSublayer:borderLayer];
}

The reason I was adding a border layer at all is because the border on the layer leaves a small artifact between the edge of the image view and the border.

OTHER TIPS

I was having the same issue as you: sublayer not being visible unless I called it on viewDidAppear.

I saw your answer but it did not work for me. I am using AutoLayout so I needed a solution that would be dynamic, not knowing my height or width of my view. My frame.size of my view I was trying to add a layer to would has a height and width value of 0 until viewDidAppear (makes sense).

After learning more about the lifecycle of UIView and UIViewController, the solution for me was to use the layoutSubviews() function of my custom UIView to add the subview to it as AutoLayout has measured the views at that point.

You can also add layers to subviews in a UIViewController in the viewDidLayoutSubviews() function as AutoLayout has measured by this point as well.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top