Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set a gradient UITableViewCell background?

I would like to create a gradient UITableViewCell background like the default Clock app that comes on the iPhone. I am not exactly sure how to accomplish that. Do I create an image and set it:

cell.contentView.backgroundColor = [UIColor alloc] initWithPatternImage:[UIImage imageNamed:@"background.png"]];

or is there another/better approach?

like image 508
Sheehan Alam Avatar asked Jul 18 '10 17:07

Sheehan Alam


2 Answers

I found the existing answer to this question but wasn't satisfied. Here's an alternative approach that requires less code, doesn't require overriding any methods, and can be applied to any view. The idea is to add a CAGradientLayer as a sublayer to the UIView's layer. I couldn't find this approach documented anywhere so I wanted to share.

Add a CAGradientLayer to any UIView as follows:

Category on UIView header - UIView+Gradient.h:

#import <UIKit/UIKit.h>

@interface UIView (Gradient)
-(void) addLinearUniformGradient:(NSArray *)stopColors;
@end

Category on UIView implementation UIView+Gradient.m:

#import "UIView+Gradient.h"
#import <QuartzCore/QuartzCore.h>

@implementation UIView (Gradient)

-(void) addLinearUniformGradient:(NSArray *)stopColors
{
    CAGradientLayer *gradient = [CAGradientLayer layer];
    gradient.frame = self.bounds;
    gradient.colors = stopColors;
    gradient.startPoint = CGPointMake(0.5f, 0.0f);
    gradient.endPoint = CGPointMake(0.5f, 1.0f);    
    [self.layer addSublayer:gradient];
}

@end

How to set the gradient on a UITableViewCell's backgroundView after creating the UITableViewCell:

// Set the gradient for the cell's background
CGRect backgroundViewFrame = cell.contentView.frame;
backgroundViewFrame.size.height = yourCellHeight;
cell.backgroundView = [[UIView alloc] initWithFrame:backgroundViewFrame];
[cell.backgroundView addLinearUniformGradient:[NSArray arrayWithObjects:
                                               (id)[[UIColor redColor] CGColor],
                                               (id)[[UIColor greenColor] CGColor], nil]];

This example only showed how to setup a simple two-stop gradient (with uniform spacing). A quick look at the CAGradientLayer documentation will show you how to setup more complex gradients.

(* EDIT FOR ADDITIONAL IMPORTANT INFORMATION *)

One additional thing to keep in mind is that if you're adding the gradient layer in a method like tableView:cellForRowAtIndexPath, the UITableViewCells are in general being reused (i.e. [tableView dequeueReusableCellWithIdentifier:@"foo"]). Because cells are being re-used, if you are always adding a gradient layer to a table view cell each time the cell is dequeued, you may end up adding several gradient layers to the tableview cell over the lifetime of the cell. This can be a source of reduced performance. This problem can occur without any change in the visible results, so it can be difficult to detect/observe. There are a few ways to solve this but one thing you may consider doing is modifying the original code above to in addition to adding the CAGradientLayer, to return the created CAGradientLayer to the caller. Then it is fairly simple to write another category method which allows the gradient layer to be removed if it is actually contained in the view:

-(BOOL) removeGradient:(CAGradientLayer *)gradientLayer
{
    // Search for gradient layer and remove it
    NSArray *layers = [self.layer sublayers];
    for ( id layer in layers ) {
        if ( layer == gradientLayer ) {
            [gradientLayer removeFromSuperlayer];
            return YES;
        }
    }

    // Failed to find the gradient layer in this view
    return NO;
}

Removing the gradient is not required for all use cases, but if your use case results in cell reuse, you may want to consider removing the gradient. One place to consider calling this method is from the UITableViewCell's prepareForReuse method.

I apologize that my original solution did not address this issue. But since it is something that can be quite subtle, I wanted to update my answer with this additional information.

like image 188
Chris Avatar answered Nov 09 '22 00:11

Chris


See this tutorial/code by Matt Coneybeare

like image 27
Michael Kessler Avatar answered Nov 08 '22 23:11

Michael Kessler