在表格视图单元格背景上放置渐变

Posted

技术标签:

【中文标题】在表格视图单元格背景上放置渐变【英文标题】:Putting gradient on tableview cells background 【发布时间】:2010-11-19 18:51:41 【问题描述】:

我一直在尝试通过多种方式为我的表格视图单元格背景添加渐变,但似乎都没有效果。我一直在尝试用石英核心图形的东西来绘制它,将背景插座放在 IB 上的不同视图中,将 imageview 放在后面,并带有代码。似乎没有人以某种方式出现在背面,我不明白出了什么问题。需要的我可以详细说明,谢谢!

【问题讨论】:

【参考方案1】:

我在this question 中找到了一些代码,并对其进行了修改以适用于我的应用程序。它适用于普通表和分组表。

//
//  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
 

使用示例(普通表):

#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; 

【讨论】:

如果我尝试将其设置为背景视图,它只会使单元格分隔符变暗,我不明白为什么它不能用作背景视图,但它可以用作选定视图? 嗯...将selectedBackgroundView 更改为backgroundView 对我来说效果很好,您的代码中可能存在其他问题,或者您对粘贴的代码进行了其他更改。也许您正在为单元格设置背景颜色和背景视图?或者您有几种类型的具有不同梯度的单元格并且您没有使用不同的单元格 ID? -- 这只是我在某个时候遇到的两个问题。

以上是关于在表格视图单元格背景上放置渐变的主要内容,如果未能解决你的问题,请参考以下文章

渐变保持在集合视图中的单元格之间快速切换

在 iPhone 上设置表格视图单元格的背景颜色

表格视图单元格内的 UIImage

如何在表格视图中放置每个单元格的图像?

如何在表格视图单元格内的视图顶部和底部放置阴影?

故事板自动布局将视图放置在表格单元格中,并将尾随到超级视图约束固定到最左侧