如何自定义分组表视图单元格的背景/边框颜色?

我想自定义一个分组样式的 UITableView 的背景和边框颜色。

我可以通过下面的方法自定义背景颜色:

tableView.contentView.backgroundColor = [UIColor greenColor];

但是边框的颜色我还是不知道怎么改。

How do I customize these two aspects of the grouped-style table view?

102621 次浏览

更新: 在 iPhone OS 3.0和更高版本的 UITableViewCell中,现在有了一个 backgroundColor属性,这使得这非常容易(特别是与 [UIColor colorWithPatternImage:]初始化器结合在一起)。但我会把2.0版本的答案留给需要的人。


这比实际上应该做的更难。当我不得不这样做的时候,我是这样做的:

您需要将 UITableViewCell 的 backoundView 属性设置为自定义 UIView,该 UIView 以适当的颜色绘制边框和背景本身。这个视图需要能够以4种不同的模式绘制边框,在一个区域的第一个单元格的顶部四舍五入,在一个区域的最后一个单元格的底部四舍五入,在一个区域的中间没有圆角的单元格,并且在包含一个单元格的区域的所有4个角上四舍五入。

Unfortunately I couldn't figure out how to have this mode set automatically, so I had to set it in the UITableViewDataSource's -cellForRowAtIndexPath method.

这是一个真正的 PITA,但我已经确认与苹果工程师,这是目前唯一的办法。

更新 下面是自定义 bg 视图的代码。有一个绘图错误,使圆角看起来有点滑稽,但我们移动到一个不同的设计和废弃的自定义背景之前,我有机会修复它。不过,这可能对你非常有帮助:

//
//  CustomCellBackgroundView.h
//
//  Created by Mike Akers on 11/21/08.
//  Copyright 2008 __MyCompanyName__. All rights reserved.
//


#import <UIKit/UIKit.h>


typedef enum  {
CustomCellBackgroundViewPositionTop,
CustomCellBackgroundViewPositionMiddle,
CustomCellBackgroundViewPositionBottom,
CustomCellBackgroundViewPositionSingle
} CustomCellBackgroundViewPosition;


@interface CustomCellBackgroundView : UIView {
UIColor *borderColor;
UIColor *fillColor;
CustomCellBackgroundViewPosition position;
}


@property(nonatomic, retain) UIColor *borderColor, *fillColor;
@property(nonatomic) CustomCellBackgroundViewPosition position;
@end


//
//  CustomCellBackgroundView.m
//
//  Created by Mike Akers on 11/21/08.
//  Copyright 2008 __MyCompanyName__. All rights reserved.
//


#import "CustomCellBackgroundView.h"


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


@implementation CustomCellBackgroundView
@synthesize borderColor, fillColor, position;


- (BOOL) isOpaque {
return NO;
}


- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// Initialization code
}
return self;
}


- (void)drawRect:(CGRect)rect {
// Drawing code
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(c, [fillColor CGColor]);
CGContextSetStrokeColorWithColor(c, [borderColor CGColor]);


if (position == CustomCellBackgroundViewPositionTop) {
CGContextFillRect(c, CGRectMake(0.0f, rect.size.height - 10.0f, rect.size.width, 10.0f));
CGContextBeginPath(c);
CGContextMoveToPoint(c, 0.0f, rect.size.height - 10.0f);
CGContextAddLineToPoint(c, 0.0f, rect.size.height);
CGContextAddLineToPoint(c, rect.size.width, rect.size.height);
CGContextAddLineToPoint(c, rect.size.width, rect.size.height - 10.0f);
CGContextStrokePath(c);
CGContextClipToRect(c, CGRectMake(0.0f, 0.0f, rect.size.width, rect.size.height - 10.0f));
} else if (position == CustomCellBackgroundViewPositionBottom) {
CGContextFillRect(c, CGRectMake(0.0f, 0.0f, rect.size.width, 10.0f));
CGContextBeginPath(c);
CGContextMoveToPoint(c, 0.0f, 10.0f);
CGContextAddLineToPoint(c, 0.0f, 0.0f);
CGContextStrokePath(c);
CGContextBeginPath(c);
CGContextMoveToPoint(c, rect.size.width, 0.0f);
CGContextAddLineToPoint(c, rect.size.width, 10.0f);
CGContextStrokePath(c);
CGContextClipToRect(c, CGRectMake(0.0f, 10.0f, rect.size.width, rect.size.height));
} else if (position == CustomCellBackgroundViewPositionMiddle) {
CGContextFillRect(c, rect);
CGContextBeginPath(c);
CGContextMoveToPoint(c, 0.0f, 0.0f);
CGContextAddLineToPoint(c, 0.0f, rect.size.height);
CGContextAddLineToPoint(c, rect.size.width, rect.size.height);
CGContextAddLineToPoint(c, rect.size.width, 0.0f);
CGContextStrokePath(c);
return; // no need to bother drawing rounded corners, so we return
}


// At this point the clip rect is set to only draw the appropriate
// corners, so we fill and stroke a rounded rect taking the entire rect


CGContextBeginPath(c);
addRoundedRectToPath(c, rect, 10.0f, 10.0f);
CGContextFillPath(c);


CGContextSetLineWidth(c, 1);
CGContextBeginPath(c);
addRoundedRectToPath(c, rect, 10.0f, 10.0f);
CGContextStrokePath(c);
}




- (void)dealloc {
[borderColor release];
[fillColor release];
[super dealloc];
}




@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
}

我一直有这个问题,并尝试了很多组合的东西,因为我注意到,对于一些细胞,它工作得很好,但不为其他人。

奇怪的是,我发现将 cell.backoundColor 设置为 lightGrayColor 是可能的,而且所有的工作都很完美——但是 blue Color 给我带来了不更新外部边缘的问题。

除非使用绿色真的很重要——也许你可以试试这个。这可能是一个特点,让人们只使用灰色,当表明一个细胞是选定的。

首先感谢这个代码。我在这个函数中进行了一些绘图改动,以消除绘图中的拐角问题。

-(void)drawRect:(CGRect)rect
{
// Drawing code


CGContextRef c = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(c, [fillColor CGColor]);
CGContextSetStrokeColorWithColor(c, [borderColor CGColor]);
CGContextSetLineWidth(c, 2);


if (position == CustomCellBackgroundViewPositionTop) {


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


maxx = maxx - 1;
maxy = maxy ;


CGContextMoveToPoint(c, minx, maxy);
CGContextAddArcToPoint(c, minx, miny, midx, miny, ROUND_SIZE);
CGContextAddArcToPoint(c, maxx, miny, maxx, maxy, ROUND_SIZE);
CGContextAddLineToPoint(c, maxx, maxy);


// Close the path
CGContextClosePath(c);
// Fill & stroke the path
CGContextDrawPath(c, kCGPathFillStroke);
return;
} else if (position == CustomCellBackgroundViewPositionBottom) {


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


maxx = maxx - 1;
maxy = maxy - 1;


CGContextMoveToPoint(c, minx, miny);
CGContextAddArcToPoint(c, minx, maxy, midx, maxy, ROUND_SIZE);
CGContextAddArcToPoint(c, maxx, maxy, maxx, miny, ROUND_SIZE);
CGContextAddLineToPoint(c, maxx, miny);
// Close the path
CGContextClosePath(c);
// Fill & stroke the path
CGContextDrawPath(c, kCGPathFillStroke);
return;
} else if (position == CustomCellBackgroundViewPositionMiddle) {
CGFloat minx = CGRectGetMinX(rect) , maxx = CGRectGetMaxX(rect) ;
CGFloat miny = CGRectGetMinY(rect) , maxy = CGRectGetMaxY(rect) ;
minx = minx + 1;
miny = miny ;


maxx = maxx - 1;
maxy = maxy ;


CGContextMoveToPoint(c, minx, miny);
CGContextAddLineToPoint(c, maxx, miny);
CGContextAddLineToPoint(c, maxx, maxy);
CGContextAddLineToPoint(c, minx, maxy);


CGContextClosePath(c);
// Fill & stroke the path
CGContextDrawPath(c, kCGPathFillStroke);
return;
}
}

谢谢你的密码,正是我要找的。我还将下面的代码添加到 Vimal 的代码中,以实现 CustomCellBackoundViewposition tionSingle 单元格的情况。(所有四个角都是圆的。)


else if (position == CustomCellBackgroundViewPositionSingle)
{
CGFloat minx = CGRectGetMinX(rect) , midx = CGRectGetMidX(rect), maxx = CGRectGetMaxX(rect) ;
CGFloat miny = CGRectGetMinY(rect) , midy = CGRectGetMidY(rect) , maxy = CGRectGetMaxY(rect) ;
minx = minx + 1;
miny = miny + 1;


maxx = maxx - 1;
maxy = maxy - 1;


CGContextMoveToPoint(c, minx, midy);
CGContextAddArcToPoint(c, minx, miny, midx, miny, ROUND_SIZE);
CGContextAddArcToPoint(c, maxx, miny, maxx, midy, ROUND_SIZE);
CGContextAddArcToPoint(c, maxx, maxy, midx, maxy, ROUND_SIZE);
CGContextAddArcToPoint(c, minx, maxy, minx, midy, ROUND_SIZE);


// Close the path
CGContextClosePath(c);
// Fill & stroke the path
CGContextDrawPath(c, kCGPathFillStroke);
return;
}

我在使用 Mike Akers 提供的 CustomCellBackoundView 代码时遇到的一个问题可能对其他人有用:

当单元格被重用时,cell.backgroundView不会自动重新绘制,对 background View 的 position 变量的更改不会影响重用的单元格。这意味着长表将错误地绘制 cell.backgroundViews给出他们的位置。

To fix this without having to create a new backgroundView every time a row is displayed, call [cell.backgroundView setNeedsDisplay] at the end of your -[UITableViewController tableView:cellForRowAtIndexPath:]. Or for a more reusable solution, override CustomCellBackgroundView's position setter to include a [self setNeedsDisplay].

非常感谢所有发布代码的人,这非常有用。

我派生了一个类似的解决方案来更改分组表视图单元格的突出显示颜色。基本上是 UITableViewCell 的 selectedBackground 视图(而不是 background 视图)。即使在 iPhone OS 3.0上,它仍然需要这个 PITA 解决方案,就我所知..。

下面的代码更改了用渐变而不是纯色来呈现突出显示。此外,边框呈现也被删除。好好享受吧。

//
//  CSCustomCellBackgroundView.h
//


#import <UIKit/UIKit.h>


typedef enum
{
CustomCellBackgroundViewPositionTop,
CustomCellBackgroundViewPositionMiddle,
CustomCellBackgroundViewPositionBottom,
CustomCellBackgroundViewPositionSingle,
CustomCellBackgroundViewPositionPlain
} CustomCellBackgroundViewPosition;


@interface CSCustomCellBackgroundView : UIView
{
CustomCellBackgroundViewPosition position;
CGGradientRef gradient;
}


@property(nonatomic) CustomCellBackgroundViewPosition position;


@end






//
//  CSCustomCellBackgroundView.m
//


#import "CSCustomCellBackgroundView.h"






#define ROUND_SIZE 10




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




@implementation CSCustomCellBackgroundView




@synthesize position;


- (BOOL) isOpaque
{
return NO;
}


- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
// Initialization code
const float* topCol = CGColorGetComponents([[UIColor redColor] CGColor]);
const float* bottomCol = CGColorGetComponents([[UIColor blueColor] CGColor]);


CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
/*
CGFloat colors[] =
{
5.0 / 255.0, 140.0 / 255.0, 245.0 / 255.0, 1.00,
1.0 / 255.0,  93.0 / 255.0, 230.0 / 255.0, 1.00,
};*/
CGFloat colors[]=
{
topCol[0], topCol[1], topCol[2], topCol[3],
bottomCol[0], bottomCol[1], bottomCol[2], bottomCol[3]
};
gradient = CGGradientCreateWithColorComponents(rgb, colors, NULL, sizeof(colors)/(sizeof(colors[0])*4));
CGColorSpaceRelease(rgb);
}
return self;
}




-(void)drawRect:(CGRect)rect
{
// Drawing code


CGContextRef c = UIGraphicsGetCurrentContext();


if (position == CustomCellBackgroundViewPositionTop)
{


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


maxx = maxx - 1;
maxy = maxy ;


CGContextMoveToPoint(c, minx, maxy);
CGContextAddArcToPoint(c, minx, miny, midx, miny, ROUND_SIZE);
CGContextAddArcToPoint(c, maxx, miny, maxx, maxy, ROUND_SIZE);
CGContextAddLineToPoint(c, maxx, maxy);


// Close the path
CGContextClosePath(c);


CGContextSaveGState(c);
CGContextClip(c);
CGContextDrawLinearGradient(c, gradient, CGPointMake(minx,miny), CGPointMake(minx,maxy), kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
CGContextRestoreGState(c);


return;
}
else if (position == CustomCellBackgroundViewPositionBottom)
{


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


maxx = maxx - 1;
maxy = maxy - 1;


CGContextMoveToPoint(c, minx, miny);
CGContextAddArcToPoint(c, minx, maxy, midx, maxy, ROUND_SIZE);
CGContextAddArcToPoint(c, maxx, maxy, maxx, miny, ROUND_SIZE);
CGContextAddLineToPoint(c, maxx, miny);
// Close the path
CGContextClosePath(c);


CGContextSaveGState(c);
CGContextClip(c);
CGContextDrawLinearGradient(c, gradient, CGPointMake(minx,miny), CGPointMake(minx,maxy), kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
CGContextRestoreGState(c);


return;
}
else if (position == CustomCellBackgroundViewPositionMiddle)
{
CGFloat minx = CGRectGetMinX(rect) , maxx = CGRectGetMaxX(rect) ;
CGFloat miny = CGRectGetMinY(rect) , maxy = CGRectGetMaxY(rect) ;
minx = minx + 1;
miny = miny + 1;


maxx = maxx - 1;
maxy = maxy ;


CGContextMoveToPoint(c, minx, miny);
CGContextAddLineToPoint(c, maxx, miny);
CGContextAddLineToPoint(c, maxx, maxy);
CGContextAddLineToPoint(c, minx, maxy);
// Close the path
CGContextClosePath(c);


CGContextSaveGState(c);
CGContextClip(c);
CGContextDrawLinearGradient(c, gradient, CGPointMake(minx,miny), CGPointMake(minx,maxy), kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
CGContextRestoreGState(c);


return;
}
else if (position == CustomCellBackgroundViewPositionSingle)
{
CGFloat minx = CGRectGetMinX(rect) , midx = CGRectGetMidX(rect), maxx = CGRectGetMaxX(rect) ;
CGFloat miny = CGRectGetMinY(rect) , midy = CGRectGetMidY(rect) , maxy = CGRectGetMaxY(rect) ;
minx = minx + 1;
miny = miny + 1;


maxx = maxx - 1;
maxy = maxy - 1;


CGContextMoveToPoint(c, minx, midy);
CGContextAddArcToPoint(c, minx, miny, midx, miny, ROUND_SIZE);
CGContextAddArcToPoint(c, maxx, miny, maxx, midy, ROUND_SIZE);
CGContextAddArcToPoint(c, maxx, maxy, midx, maxy, ROUND_SIZE);
CGContextAddArcToPoint(c, minx, maxy, minx, midy, ROUND_SIZE);
// Close the path
CGContextClosePath(c);


CGContextSaveGState(c);
CGContextClip(c);
CGContextDrawLinearGradient(c, gradient, CGPointMake(minx,miny), CGPointMake(minx,maxy), kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
CGContextRestoreGState(c);


return;
}
else if (position == CustomCellBackgroundViewPositionPlain) {
CGFloat minx = CGRectGetMinX(rect);
CGFloat miny = CGRectGetMinY(rect), maxy = CGRectGetMaxY(rect) ;
CGContextDrawLinearGradient(c, gradient, CGPointMake(minx,miny), CGPointMake(minx,maxy), kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
return;
}


}


- (void)dealloc
{
CGGradientRelease(gradient);
[super dealloc];
}




- (void) setPosition:(CustomCellBackgroundViewPosition)inPosition
{
if(position != inPosition)
{
position = inPosition;
[self setNeedsDisplay];
}
}


@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
}

Thanks for this super helpful post. In case anyone out there (like me!) wants to just have a completely empty cell background in lieu of customizing it through images/text/other content in IB and cannot figure out how the hell to get rid of the dumb border/padding/background even though you set it to clear in IB... here's the code I used that did the trick!


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


static NSString *cellId = @"cellId";


UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: cellId];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:@"EditTableViewCell" owner:self options:nil];
cell = cellIBOutlet;
self.cellIBOutlet = nil;
}


cell.backgroundView = [[[UIView alloc] initWithFrame: CGRectZero] autorelease];
[cell.backgroundView setNeedsDisplay];


... any other cell customizations ...


return cell;
}

希望这能帮到其他人! 看起来很有效。

You can customize the border color by setting

tableView.separatorColor

我知道答案与更改分组表单元格有关,但是如果有人想要更改桌面视图的背景颜色:

你不仅需要设置:

tableview.backgroundColor = color;

您还需要更改或删除背景视图:

tableview.backgroundView = nil;

更改表视图边框颜色:

In.h:

#import <QuartzCore/QuartzCore.h>

在. m:

tableView.layer.masksToBounds=YES;
tableView.layer.borderWidth = 1.0f;
tableView.layer.borderColor = [UIColor whiteColor].CGColor;

This task can be easily done using 真漂亮 by adding about 5 lines of code. If you use nib files or storyboard, also do not forget to apply 这个小黑客 . When you use this approach, you should subclass your cell from PrettyTableViewCell:

#import <PrettyKit/PrettyKit.h>


@class RRSearchHistoryItem;


@interface RRSearchHistoryCell : PrettyTableViewCell

这是我的 cellForRowAtIndexPath的例子:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = @"RRSearchHistoryCell";


RRSearchHistoryCell *cell = (RRSearchHistoryCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];


if ( cell == nil ) {


NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"RRSearchHistoryCell" owner:self options:nil];
cell = topLevelObjects[0];
cell.gradientStartColor = RGB(0xffffff);
cell.gradientEndColor = RGB(0xf3f3f3);


}


RRSearchHistoryItem *item = _historyTableData[indexPath.row];
[cell setHistoryItem:item];




[cell prepareForTableView:tableView indexPath:indexPath];


return cell;
}