How to optimize UITableViewCell rendering, when using CGContextDrawLinearGradient
I have a UITableView where I am trying to get the best possible scrolling performance.
The cell does not contain any subviews, all is done in the drawRect method.
Each cell has a white line at the top, a grey line at the bottom and a linear gradient between top and bottom. On top of this background is some text and an image.
I can see from using instruments that the main portion (>50%) of the runtime when scrolling comes from the drawing of the linear gradient. Actually almost all of that comes from the call to CGContextDrawLinearGradient.
Is there a good way to optimize this开发者_StackOverflow? I am thinking, either cache the linear gradient some way, or maybe draw it in another way... Maybe draw a one pixel wide and then stretch it?
Here is some of my code:
- (void)drawRect:(CGRect)rect
{
[self drawCellBackground:rect];
[self drawSeparator:rect];
....
}
- (void)drawCellBackground:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGColorRef notQuiteWhiteColor = [UIColor colorWithRed:245.0/255.0 green:245.0/255.0
blue:245.0/255.0 alpha:1.0].CGColor;
CGColorRef lightGrayColor = [UIColor colorWithRed:235.0/255.0 green:235.0/255.0
blue:235.0/255.0 alpha:1.0].CGColor;
drawLinearGradient(context, rect, notQuiteWhiteColor, lightGrayColor);
}
From a separate .c file:
void drawLinearGradient(CGContextRef context, CGRect rect, CGColorRef startColor, CGColorRef endColor)
{
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat locations[] = { 0.0, 1.0 };
NSArray *colors = [NSArray arrayWithObjects:(id)startColor, (id)endColor, nil];
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace,
(CFArrayRef) colors, locations);
CGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect));
CGContextSaveGState(context);
CGContextAddRect(context, rect);
CGContextClip(context);
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
CGContextRestoreGState(context);
CGGradientRelease(gradient);
CGColorSpaceRelease(colorSpace);
}
If you absolutely want to stick to using drawRect: (which I believe gives better performance than separate views on older devices), why not prerender your gradient into a CGImage or UIImage, then use that to draw in -drawRect: ?
Also, you can create your gradient ahead of time:
static CGGradientRef GetCellBackgroundGradient()
{
static CGGradientRef gradient = NULL ;
if ( !gradient )
{
gradient = // create your CGGradientRef here
}
return gradient;
}
For high performance code you want to preallocate as many things (memory/objects) as possible.
Are you reusing table view cells properly? If so, in this case I think you will be better off using subviews on your table view instead of doing all drawing in drawRect:
. By using subviews, and assuming the gradient is the same for all cells, the gradient would only have to be drawn once per reusable cell. When it gets recycled with new content, only the text and image views will need to be updated instead of having to draw the gradient all over again.
精彩评论