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.
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.