Iphone – Need to override drawrect if your UIView is merely a container

drawrectiphoneuiview

According to Apple's docs, "Subclasses need not override -[UIView drawRect:] if the subclass is a container for other views."

I have a custom UIView subclass that is indeed merely a container for other views. Yet the contained views aren't getting drawn. Here's the pertinent code that sets up the custom UIView subclass:

- (id)initWithFrame:(CGRect)frame
{
    if ((self = [super initWithFrame:frame]))
    {
        // Consists of both an "on" light and an "off" light. We flick between the two depending upon our state.
        self.onLight = [[[LoyaltyCardNumberView alloc] initWithFrame:frame] autorelease];
        self.onLight.backgroundColor = [UIColor clearColor];
        self.onLight.on = YES;
        [self addSubview:self.onLight];

        self.offLight = [[[LoyaltyCardNumberView alloc] initWithFrame:frame] autorelease];
        self.offLight.backgroundColor = [UIColor clearColor];
        self.offLight.on = NO;
        [self addSubview:self.offLight];

        self.on = NO;
    }
    return self;
}

When I run the code that displays this custom UIView, nothing shows up. But when I add a drawRect method…

    - (void)drawRect:(CGRect)rect
    {
        [self.onLight drawRect:rect];
        [self.offLight drawRect:rect];
    }

…the subviews display. (Clearly, this isn't the right way to be doing this, not only because it's contrary to what the docs say, but because it -always- displays both subviews, completely ignoring some other code in my UIView that sets the hidden property of one of the views, it ignores the z-ordering, etc.)

Anyway, the main question: why don't my subviews display when I'm not overriding drawRect:?

Thanks!

UPDATE:

Just to make sure that the problem doesn't lie in my custom subviews, I added in a UILabel as well. So the code reads:

- (id)initWithFrame:(CGRect)frame
{
    if ((self = [super initWithFrame:frame]))
    {
        // Consists of both an "on" light and an "off" light. We flick between the two depending upon our state.
        self.onLight = [[[LoyaltyCardNumberView alloc] initWithFrame:frame] autorelease];
        self.onLight.backgroundColor = [UIColor clearColor];
        self.onLight.on = YES;
        [self addSubview:self.onLight];

        self.offLight = [[[LoyaltyCardNumberView alloc] initWithFrame:frame] autorelease];
        self.offLight.backgroundColor = [UIColor clearColor];
        self.offLight.on = NO;
        [self addSubview:self.offLight];

        self.on = NO;

        UILabel* xLabel = [[[UILabel alloc] initWithFrame:frame] autorelease];
        xLabel.text = @"X";
        [self addSubview:xLabel];
    }
    return self;

The "X" doesn't display either.

UPDATE 2:

Here's the code that invokes my custom UIView (OffOnLightView):

            // Container for all of the OffOnLightViews...
            self.stampSuperView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)] autorelease];
            [self.view addSubview:self.stampSuperView];

            // Draw the stamps into the 'stamp superview'.
            NSInteger numberOfCardSpaces = (awardType == None) ? 3 : 10;
            for (NSInteger i = 1; i <= numberOfCardSpaces; i++)
            {
                OffOnLightView* newNumberView = [[[OffOnLightView alloc] initWithFrame:[self frameForStampWithOrdinal:i awardType:awardType]] autorelease];
                newNumberView.on = (i <= self.place.checkInCount.intValue);
                newNumberView.number = [NSString stringWithFormat:@"%d", i];
                [self.stampSuperView addSubview:newNumberView];
            }

Best Answer

Your subviews should have their frame initialized to the bounds of the parent uiview. Subviews are in a different coordinate system that is relative to the frame of the parent.

self.onLight = [[[LoyaltyCardNumberView alloc] initWithFrame:self.bounds] autorelease];
Related Topic