views:

112

answers:

1

Hi All.

I have a somewhat special situation that I need help with. I have a CustomView which I am placing in every UITableViewCell in my UITableView. No problems there.

Within my CustomView is a UILabel which displays some text given to it. Depending on the length of the text, the width of the CustomView grows/shrinks. All fine.

The problem I am having is with a sublayer in my CustomView which is a gradient (CAGradientLayer). The gradient size will not grow/shrink off screen on cells not in view.

Let me show you some code... I create my CustomView like so:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *CellIdentifier = @"Cell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

    CustomView *custom = [[CustomView alloc] init];
    custom.tag = 777;
    [cell.contentView addSubview:custom];
    [custom release];

}

}

I don't initWithFrame at this stage as the cell could get reused and the width is always wrong. Once the cell is there, I call a method configureCell: where I do the following:

CGSize teamMaxSize = CGSizeMake(300, 18);
CGSize teamNewSize = [[managedObject valueForKey:@"category"] 
    sizeWithFont:[UIFont systemFontOfSize:kFontSizeTeam]
    constrainedToSize:teamMaxSize
    lineBreakMode:UILineBreakModeWordWrap];

CustomView *lozenge = (CustomView *) [cell.contentView viewWithTag:777];
lozenge.frame = CGRectMake(10, 5, teamNewSize.width+12, 18);
[lozenge resetSize];
[lozenge setLabel:[managedObject valueForKey:@"category"]];

This works fine, the width of my CustomView is setup as per the length of the 'category' key. The resetSize; method above simply resizes the UILabel I mentioned before to the new frame of the CustomView before I fill it with the value.

Anyway, back to my issue. I am creating the background gradient in the drawRect: method of my CustomView. It works fine, however is the size of the CustomView at init. After I resize I need to resize the gradient.frame. So, I tried adding

gradient.frame = self.bounds

When I call resetSize in my aforementioned code. However when scrolling through the UITableView I can see the gradient literally filling from left to right as it loads into view. Is there anyway I can get this to happen 'off screen' so the CustomView is filled with the gradient as soon as it appears?

+1  A: 

Instead of creating a gradient in drawRect:, have you considered using CAGradientLayer as the layer class of your custom view, e.g.:

+ (Class)layerClass
{
    return [CAGradientLayer class];
}

Then you can perform any setup of your gradient in your initializer, via self.layer.

bosmacs
but the width of my gradient cannot be set when I initialize the CustomView... I have to wait...
mootymoots
I'm not sure I understand exactly what you're trying to do, but if you are trying to create a gradient background for your cell, I'd suggest creating a simple `CustomBackgroundView` class as described (with a `CAGradientLayer` backing) and attaching it to your cell's `backgroundView` property. It should be automatically sized appropriately for your cell, and you can do the rest of your custom drawing in your `CustomView`.
bosmacs
I'm creating a gradient in the background of my CustomView. Imagine the custom view as a lozenge button with a line of text in it. It is within my cell with other objects...
mootymoots
On further consideration, is `gradient.frame = self.bounds` happening within a `UIView` animation context?
bosmacs
No, it's just within a custom method to resize the UILabel.
mootymoots
It sounds like it's animating the frame change when you want it to take place immediately. Just for kicks you could try wrapping the call with `[UIView setAnimationsEnabled:NO]; ... [UIView setAnimationsEnabled:YES];` or temporarily disable them entirely.
bosmacs
it made no difference I'm afraid.
mootymoots
Oops, that probably should have been `[UIView beginAnimations:nil context:nil]; [UIView setAnimationsEnabled:NO]; gradient.frame = self.bounds; [UIView commitAnimations];` -- I'll edit the answer if this works for you.
bosmacs
No, that made my entire table react strangely...
mootymoots
Is this happening on the simulator, device, or both?
bosmacs
Also, if `gradient` above is a `CAGradientLayer` and not a `UIView` (as I hastily assumed), perhaps this would work: [CATransaction begin]; [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; gradient.frame = self.bounds; [CATransaction commit];
bosmacs