¿Cómo personalizar los colores de fondo / borde de una celda de vista de tabla agrupada?

Me gustaría personalizar el fondo y el color del borde de un UITableView de estilo agrupado.

Pude personalizar el color de fondo usando lo siguiente:

tableView.contentView.backgroundColor = [UIColor greenColor]; 

Pero el color del borde sigue siendo algo que no sé cómo cambiar.

¿Cómo personalizo estos dos aspectos de la vista de tabla de estilo agrupado?

ACTUALIZACIÓN: en iPhone OS 3.0 y UITableViewCell posteriores, UITableViewCell ahora tiene una propiedad backgroundColor que hace esto realmente fácil (especialmente en combinación con el [UIColor colorWithPatternImage:] ). Pero dejaré aquí la versión 2.0 de la respuesta para cualquiera que lo necesite …


Es más difícil de lo que realmente debería ser. Así es como hice esto cuando tuve que hacerlo:

Debe configurar la propiedad backgroundView de UITableViewCell en una UIView personalizada que dibuje el borde y el fondo en los colores apropiados. Esta vista debe poder dibujar los bordes en 4 modos diferentes, redondeados en la parte superior para la primera celda en una sección, redondeados en la parte inferior para la última celda en una sección, no hay esquinas redondeadas para las celdas en el medio de una sección y redondeado en las 4 esquinas para las secciones que contienen una celda.

Lamentablemente no pude entender cómo configurar este modo automáticamente, así que tuve que configurarlo en el método de UITableViewDataSource -cellForRowAtIndexPath.

Es un PITA real, pero he confirmado con los ingenieros de Apple que esta es actualmente la única forma.

Actualizar Aquí está el código para esa vista personalizada de bg. Hay un error de dibujo que hace que las esquinas redondeadas se vean un poco divertidas, pero cambiamos a un diseño diferente y descartamos los fondos personalizados antes de que tuviera la oportunidad de solucionarlo. Aún así, esto probablemente sea muy útil para ti:

 // // CustomCellBackgroundView.h // // Created by Mike Akers on 11/21/08. // Copyright 2008 __MyCompanyName__. All rights reserved. // #import  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 } 

Sé que las respuestas están relacionadas con el cambio de celdas de tabla agrupadas, pero en caso de que alguien quiera cambiar también el color de fondo de la tabla:

No solo necesitas configurar:

 tableview.backgroundColor = color; 

También necesita cambiar o deshacerse de la vista de fondo:

 tableview.backgroundView = nil; 

Antes que nada, gracias por este código. He realizado algunos cambios de dibujo en esta función para eliminar el problema de esquina en el dibujo.

 -(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; } } 

Gracias por el código, es justo lo que estaba buscando. También agregué el siguiente código al código de Vimal para implementar el caso de una celda CustomCellBackgroundViewPositionSingle. (Las cuatro esquinas están redondeadas)

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

Una cosa que encontré con el código CustomCellBackgroundView anterior de Mike Akers que podría ser útil para otros:

cell.backgroundView no se vuelve a dibujar automáticamente cuando se reutilizan las celdas, y los cambios en la posición var de la vista de fondo no afectan a las celdas reutilizadas. Eso significa que las tablas largas habrán dibujado cell.backgroundViews incorrectamente cell.backgroundViews sus posiciones.

Para arreglar esto sin tener que crear una nueva vista de fondo cada vez que se muestre una fila, llame [cell.backgroundView setNeedsDisplay] al final de su -[UITableViewController tableView:cellForRowAtIndexPath:] . O para una solución más reutilizable, anule el ajustador de posición de CustomCellBackgroundView para incluir un [self setNeedsDisplay] .

Gracias por esta publicación muy útil. En caso de que alguien (¡como yo!) Quiera tener un fondo de celda completamente vacío en lugar de personalizarlo a través de imágenes / texto / otro contenido en IB y no puede encontrar la manera de deshacerse del estúpido borde / relleno / a pesar de que configuró para borrar en IB … aquí está el código que usé que hizo el truco!

 - (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; } 

¡Espero que eso ayude a alguien más! Parece funcionar como un encanto.

Muchas gracias a todos los que publicaron su código. Esto es muy útil

Obtuve una solución similar para cambiar el color de resaltado para las celdas de vista de tabla agrupadas. Básicamente, la vista seleccionada de UITableViewCell (no la vista de fondo). Que incluso en iPhone OS 3.0 todavía necesita esta solución PITA, por lo que puedo decir …

El siguiente código tiene los cambios para representar el resaltado con un degradado en lugar de un color sólido. También se elimina la representación de bordes. Disfrutar.

 // // CSCustomCellBackgroundView.h // #import  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 } 

Puede personalizar el color del borde estableciendo

 tableView.separatorColor 

Para cambiar el color del borde de la vista de tabla:

In.h:

 #import  

En m:

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

Esta tarea se puede hacer fácilmente usando PrettyKit agregando alrededor de 5 líneas de código. Si usa archivos nib o storyboard , no olvide aplicar este pequeño truco . Cuando utiliza este enfoque, debe subclasificar su celda de PrettyTableViewCell :

 #import  @class RRSearchHistoryItem; @interface RRSearchHistoryCell : PrettyTableViewCell 

Este es un ejemplo de mi 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; } 

He tenido problemas con esto y probé muchas combinaciones de cosas, ya que noté que para algunas células funcionaba bien, pero no para otras.

Extrañamente descubrí que es posible establecer cell.backgroundColor en lightGrayColor y todo funciona perfectamente, pero blueColor me causó problemas para no actualizar los bordes externos.

A menos que sea realmente importante usar verde, tal vez quieras probar esto. Es posible que esta sea una característica para que la gente use solo colores grises cuando se selecciona una celda.