2

I have been trying to put a gradient to my table view cells background with several ways and none seem to work. I've been trying to draw it with quarz core graphics thing, putting background outlet to a different view on IB, putting imageview on the back with code. None seem to show up on the back somehow, I don't get what is wrong. I can elaborate if needed, thanks!

Samuli Lehtonen
  • 3,840
  • 5
  • 39
  • 49

1 Answers1

2

I found some code in this question and adapted it to work with my application. It works great with both plain and grouped tables.

//
//  UAGradientCellBackgroundLayer.h
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

#import <QuartzCore/QuartzCore.h>

@class UAGradientCellBackgroundView;

@interface UAGradientCellBackgroundLayer : CAGradientLayer {
    CGFloat     *colorComponents;
    BOOL        _override;
}

@property(nonatomic,assign) BOOL override;

- (void)setColorComponents:(CGFloat *)components;

@end

//
//  UAGradientCellBackgroundLayer.m
//

#import "UAGradientCellBackgroundLayer.h"
#import "UAGradientCellBackgroundView.h"

#define TABLE_CELL_BACKGROUND                                   {1, 1, 1, 1, 204/255.0, 204/255.0, 204/255.0, 1}        // #FFFFFF and #DDDDDD

@implementation UAGradientCellBackgroundLayer

@synthesize override = _override;

///////////////////////////////////////////////////////////////////////////////////////////////////
- (id)init { 
    if ((self = [super init])) {
        colorComponents = NSZoneMalloc(NSDefaultMallocZone(), 8*sizeof(CGFloat));
        CGFloat c[8] = TABLE_CELL_BACKGROUND;
        for (int i = 0; i < 8; i++) {
            colorComponents[i] = c[i];
        }
        // self.cornerRadius = 10;
        // self.backgroundColor = [UIColor clearColor].CGColor;
    }
    return self;
}

- (void) dealloc {
    NSZoneFree(NSDefaultMallocZone(), colorComponents);
    [super dealloc];
}
- (void)display {
    if (_override) {
        self.colors =
        [NSArray arrayWithObjects:
         (id)[UIColor colorWithRed:colorComponents[0] green:colorComponents[1] blue:colorComponents[2] alpha:colorComponents[3]].CGColor,
         (id)[UIColor colorWithRed:colorComponents[4] green:colorComponents[5] blue:colorComponents[6] alpha:colorComponents[7]].CGColor,
         nil];
    } else {
        self.colors =
        [NSArray arrayWithObjects:
         (id)[UIColor clearColor].CGColor,
         (id)[UIColor clearColor].CGColor,
         nil];
    }
    [super display];
}

- (void)setColorComponents:(CGFloat *)components {
    for (int i = 0; i < 8; i++) {
        colorComponents[i] = components[i];
    }
}

@end 

//
//  UAGradientCellBackgroundView.h
//

#import <Foundation/Foundation.h>

#import <UIKit/UIKit.h>

typedef enum  {
    UAGradientCellBackgroundViewPositionMiddle = 0,
    UAGradientCellBackgroundViewPositionTop,
    UAGradientCellBackgroundViewPositionBottom,
    UAGradientCellBackgroundViewPositionSingle,
    UAGradientCellBackgroundViewPositionPlain
} UAGradientCellBackgroundViewPosition;

@interface UAGradientCellBackgroundView : UIView {
    UAGradientCellBackgroundViewPosition position;
    CGFloat colors[8];
}

@property(nonatomic, assign) UAGradientCellBackgroundViewPosition position;

- (void)setColors:(CGFloat[8])comps;

@end

//
//  UAGradientCellBackgroundView.m
//

#import "UAGradientCellBackgroundView.h"
#import "UAGradientCellBackgroundLayer.h"
#import <QuartzCore/QuartzCore.h>

#define kDefaultMargin                                          10
#define TABLE_CELL_BACKGROUND                                   {1, 1, 1, 1, 204/255.0, 204/255.0, 204/255.0, 1}        // #FFFFFF and #DDDDDD

static void addRoundedRectToPath(CGContextRef context, CGRect rect,
                                 float ovalWidth,float ovalHeight);

@implementation UAGradientCellBackgroundView

@synthesize position;

//////////////////////////////////////////////////////////////////////
// PLAIN CELL
//
// layerClass
//
// returns a CAGradientLayer class as the default layer class for this view
//
+ (Class)layerClass {
    return [UAGradientCellBackgroundLayer class];
}

//////////////////////////////////////////////////////////////////////
- (void)updateLayer {
    UAGradientCellBackgroundLayer* layer = (UAGradientCellBackgroundLayer*)self.layer;
        // This is dramatically faster than calling drawRect.
    [layer setColorComponents:colors];
    layer.override = (self.position == UAGradientCellBackgroundViewPositionPlain);
    [layer setNeedsDisplay];
}

////////////////////////////////////////////////////////////////////
// GROUPED CELL
- (void)setColors:(CGFloat[8])comps {
    for (int i = 0; i < 8; i++) {
        colors[i] = comps[i];
    }
}

- (BOOL)isOpaque {
    return YES;
}

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self != nil) {
        CGFloat comps[8] = TABLE_CELL_BACKGROUND;
        [self setColors:comps];
    }
    return self;
}

- (void)debugView:(UIView *)view {
    NSLog(@"%@ - %@", view.backgroundColor, [[view class] description]);
    for (UIView* child in view.subviews) {
        [self debugView:child];
    }
}

-(void)drawRect:(CGRect)aRect {
    [super drawRect:aRect];
    // Drawing code
    if (position == UAGradientCellBackgroundViewPositionPlain) {
        return;
    }

    CGContextRef c = UIGraphicsGetCurrentContext(); 

    // TODO - Dirty, Dirty hack to fix the background black corners on pop issue. doesnt handle rotation.
//  CGContextSetFillColorWithColor(c, [UAColor offsetPinstripesColor].CGColor);
//  CGContextFillRect(c, aRect);

    int lineWidth = 1;

    CGRect rect = [self bounds];
    rect.size.width -= lineWidth;
    rect.size.height -= lineWidth;
    rect.origin.x += lineWidth / 2.0;
    rect.origin.y += lineWidth / 2.0;

    CGFloat minx = CGRectGetMinX(rect), midx = CGRectGetMidX(rect), maxx = CGRectGetMaxX(rect);
    CGFloat miny = CGRectGetMinY(rect), midy = CGRectGetMidY(rect), maxy = CGRectGetMaxY(rect);
    miny -= 1;

    CGFloat locations[2] = { 0.0, 1.0 };    
    CGColorSpaceRef myColorspace = CGColorSpaceCreateDeviceRGB();
    CGGradientRef myGradient = nil;

    CGContextSetStrokeColorWithColor(c, [UIColor darkGrayColor].CGColor);
    CGContextSetLineWidth(c, lineWidth);
    CGContextSetAllowsAntialiasing(c, YES);
    CGContextSetShouldAntialias(c, YES);

    if (position == UAGradientCellBackgroundViewPositionTop) {
        miny += 1;

        CGMutablePathRef path = CGPathCreateMutable();
        CGPathMoveToPoint(path, NULL, minx, maxy);
        CGPathAddArcToPoint(path, NULL, minx, miny, midx, miny, kDefaultMargin);
        CGPathAddArcToPoint(path, NULL, maxx, miny, maxx, maxy, kDefaultMargin);
        CGPathAddLineToPoint(path, NULL, maxx, maxy);
        CGPathAddLineToPoint(path, NULL, minx, maxy);
        CGPathCloseSubpath(path);

        // Fill and stroke the path
        CGContextSaveGState(c);
        CGContextAddPath(c, path);
        CGContextClip(c);

        myGradient = CGGradientCreateWithColorComponents(myColorspace, colors, locations, 2);
        CGContextDrawLinearGradient(c, myGradient, CGPointMake(minx,miny), CGPointMake(minx,maxy), 0);

        CGContextAddPath(c, path);
        CGPathRelease(path);
        CGContextStrokePath(c);
        CGContextRestoreGState(c);

    } else if (position == UAGradientCellBackgroundViewPositionBottom) {
        //maxy -= 1; // -1 for the shadow 

        CGMutablePathRef path = CGPathCreateMutable();
        CGPathMoveToPoint(path, NULL, minx, miny);
        CGPathAddArcToPoint(path, NULL, minx, maxy, midx, maxy, kDefaultMargin);
        CGPathAddArcToPoint(path, NULL, maxx, maxy, maxx, miny, kDefaultMargin);
        CGPathAddLineToPoint(path, NULL, maxx, miny);
        CGPathAddLineToPoint(path, NULL, minx, miny);
        CGPathCloseSubpath(path);

        // Fill and stroke the path
        CGContextSaveGState(c);
        CGContextAddPath(c, path);
        CGContextClip(c);

        myGradient = CGGradientCreateWithColorComponents(myColorspace, colors, locations, 2);
        CGContextDrawLinearGradient(c, myGradient, CGPointMake(minx,miny), CGPointMake(minx,maxy), 0);

        CGContextAddPath(c, path);
        CGPathRelease(path);
        CGContextStrokePath(c);
        CGContextRestoreGState(c);


    } else if (position == UAGradientCellBackgroundViewPositionMiddle) {

        CGMutablePathRef path = CGPathCreateMutable();
        CGPathMoveToPoint(path, NULL, minx, miny);
        CGPathAddLineToPoint(path, NULL, maxx, miny);
        CGPathAddLineToPoint(path, NULL, maxx, maxy);
        CGPathAddLineToPoint(path, NULL, minx, maxy);
        CGPathAddLineToPoint(path, NULL, minx, miny);
        CGPathCloseSubpath(path);

        // Fill and stroke the path
        CGContextSaveGState(c);
        CGContextAddPath(c, path);
        CGContextClip(c);

        myGradient = CGGradientCreateWithColorComponents(myColorspace, colors, locations, 2);
        CGContextDrawLinearGradient(c, myGradient, CGPointMake(minx,miny), CGPointMake(minx,maxy), 0);

        CGContextAddPath(c, path);
        CGPathRelease(path);
        CGContextStrokePath(c);
        CGContextRestoreGState(c);

    } else if (position == UAGradientCellBackgroundViewPositionSingle) {
        miny += 1;
        //maxy -= 1; // -1 for the shadow 

        CGMutablePathRef path = CGPathCreateMutable();
        CGPathMoveToPoint(path, NULL, minx, midy);
        CGPathAddArcToPoint(path, NULL, minx, miny, midx, miny, kDefaultMargin);
        CGPathAddArcToPoint(path, NULL, maxx, miny, maxx, midy, kDefaultMargin);
        CGPathAddArcToPoint(path, NULL, maxx, maxy, midx, maxy, kDefaultMargin);
        CGPathAddArcToPoint(path, NULL, minx, maxy, minx, midy, kDefaultMargin);
        CGPathCloseSubpath(path);

        // Shadow
//      CGContextAddPath(c, path);
//      CGContextSaveGState(c);
//      CGContextSetShadow(c, CGSizeMake(0, -1), 1);
//      CGContextFillPath(c);

        // Fill and stroke the path
        CGContextSaveGState(c);
        CGContextAddPath(c, path);
        CGContextClip(c);


        myGradient = CGGradientCreateWithColorComponents(myColorspace, colors, locations, 2);
        CGContextDrawLinearGradient(c, myGradient, CGPointMake(minx,miny), CGPointMake(minx,maxy), 0);

        CGContextAddPath(c, path);
        CGPathRelease(path);
        CGContextStrokePath(c);
        CGContextRestoreGState(c);

    }
    CGColorSpaceRelease(myColorspace);
    CGGradientRelease(myGradient);
    return;
}

- (void)setPosition:(UAGradientCellBackgroundViewPosition)newPosition {
    if (position != newPosition) {
        position = newPosition;
        [self updateLayer];
    }
}

@end

static void addRoundedRectToPath(CGContextRef context, CGRect rect, float ovalWidth,float ovalHeight) {
    float fw, fh;

    if (ovalWidth == 0 || ovalHeight == 0) {// 1
        CGContextAddRect(context, rect);
        return;
    }

    CGContextSaveGState(context);// 2

    CGContextTranslateCTM (context, CGRectGetMinX(rect),// 3
                           CGRectGetMinY(rect));
    CGContextScaleCTM (context, ovalWidth, ovalHeight);// 4
    fw = CGRectGetWidth (rect) / ovalWidth;// 5
    fh = CGRectGetHeight (rect) / ovalHeight;// 6

    CGContextMoveToPoint(context, fw, fh/2); // 7
    CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1);// 8
    CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1);// 9
    CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1);// 10
    CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1); // 11
    CGContextClosePath(context);// 12

    CGContextRestoreGState(context);// 13
} 

Usage sample (plain table):

#import "UAGradientCellBackgroundView.h" 
CGFloat COLORS[8] = { 0.0/255, 0.0/255, 255.0/255, 1.0, 0.0/255, 0.0/255, 0.0/255, 1.0 }
...

- (UITableViewCell *)tableView:(UITableView *)table cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    NSString *cellID = @"CellID";

    // create cell
    UITableViewCell *cell = (UITableViewCell *)[table dequeueReusableCellWithIdentifier:cellID];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID] autorelease];

        UAGradientCellBackgroundView *bgView = [[[UAGradientCellBackgroundView alloc] initWithFrame:CGRectZero] autorelease];
        [bgView setBackgroundColor:[UIColor clearColor]];
        [bgView setColors:COLORS];
        [bgView setPosition:UAGradientCellBackgroundViewPositionPlain];
        cell.selectedBackgroundView = bgView;
        cell.textLabel.backgroundColor = [UIColor clearColor];

        cell.imageView.image = [UIImage imageNamed:@"cellimg.png"];
    }

    cell.textLabel.text = @"Text";
    return cell; 
}
Community
  • 1
  • 1
cristis
  • 1,986
  • 16
  • 22
  • If I try to set it as background view it only makes the cell seperators darker, I don't get why it won't work as background view, but it works as selected view? – Samuli Lehtonen Nov 19 '10 at 21:32
  • Umm... changing `selectedBackgroundView` to `backgroundView` works just fine for me, there's probably some other issue in your code or you made some other changes to the code pasted. Maybe you're setting both the background color and the background view for the cells? Or you have several types of cells with different gradients and you're not using different cell IDs? -- these are just two problems I ran into at some point. – cristis Nov 19 '10 at 22:06