iosobjective-cuiviewcashapelayerinitwithframe

Sublayer only draws when created in initWithFrame, not initWithCoder


I have a custom view with a sublayer (CAShapeLayer) and subview (UILabel). When I create the layer in initWithCoder and set the background color, it always shows up as black. However, if I move the code into initWithFrame, the color shows up successfully.

Are we not supposed to create sublayers in initWithCoder?

Here is the only way I can get my code to work:

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.colorLayer = [CAShapeLayer layer];
        self.colorLayer.opacity = 1.0;
        [self.layer addSublayer:self.colorLayer];
    }
    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {

        self.textLabel = [[UILabel alloc] initWithFrame:self.bounds];
        self.textLabel.font = [UIFont primaryBoldFontWithSize:12];
        self.textLabel.textColor = [UIColor whiteColor];
        self.textLabel.textAlignment = NSTextAlignmentCenter;
        self.textLabel.backgroundColor = [UIColor clearColor];
        [self addSubview:self.textLabel];
    }

    return self;

}

- (void)drawRect:(CGRect)rect {
    //Custom drawing of sublayer
}

UPDATE:

Turns out in my drawRect I was setting the fill color wrong. I should have used colorLayer.fillColor = myColor.CGColor instead of [myColor setFill] then [path fill]


Solution

  • The difference between initWithFrame: and initWithCoder: is that initWithCoder: is called when the view is created from storyboard/nib.

    If you add it programatically, for example:

    UIView *v = [[UIView alloc] initWithFrame:...];
    [self.view addSubview:v];
    

    initWithFrame: is called.

    The good idea is to create base init method and call it in both init. In that way the initialisation sets up all of the properties in both scenario, when the view is added programatically or in storyboard.

    For example:

    -(void)baseInit {
        self.colorLayer = [CAShapeLayer layer];
        self.colorLayer.opacity = 1.0;
        //... other initialisation
    }
    
    - (id)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self) {
            [self baseInit];
        }
        return self;
    }
    
    - (id)initWithCoder:(NSCoder *)aDecoder {
        self = [super initWithCoder:aDecoder];
        if (self) {
    
            [self baseInit];
        }
    
        return self;
    }