La subvista UITableViewCell desaparece cuando se selecciona la celda

Estoy implementando una vista de tabla de selección de color en la que el usuario puede seleccionar entre, por ejemplo, 10 colores (depende del producto). El usuario también puede seleccionar otras opciones (como la capacidad del disco duro, …).

Todas las opciones de color están dentro de su propia sección de vista de tabla.

Quiero mostrar un pequeño cuadrado a la izquierda de la etiqueta de texto que muestra el color real.

Ahora estoy agregando un UIView cuadrado simple, le doy el color de fondo correcto, así:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:RMProductAttributesCellID]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:RMProductAttributesCellID] autorelease]; cell.indentationWidth = 44 - 8; UIView *colorThumb = [[[UIView alloc] initWithFrame:CGRectMake(8, 8, 28, 28)] autorelease]; colorThumb.tag = RMProductAttributesCellColorThumbTag; colorThumb.hidden = YES; [cell.contentView addSubview:colorThumb]; } RMProductAttribute *attr = (RMProductAttribute *)[_product.attributes objectAtIndex:indexPath.section]; RMProductAttributeValue *value = (RMProductAttributeValue *)[attr.values objectAtIndex:indexPath.row]; cell.textLabel.text = value.name; cell.textLabel.backgroundColor = [UIColor clearColor]; UIView *colorThumb = [cell viewWithTag:RMProductAttributesCellColorThumbTag]; colorThumb.hidden = !attr.isColor; cell.indentationLevel = (attr.isColor ? 1 : 0); if (attr.isColor) { colorThumb.layer.cornerRadius = 6.0; colorThumb.backgroundColor = value.color; } [self updateCell:cell atIndexPath:indexPath]; return cell; } 

Esto se muestra bien sin problemas.

Mi único problema es que cuando selecciono una fila de “color”, durante la animación de selección de fundido a azul, mi UIView personalizada (colorThumb) está oculta. Se vuelve a visualizar justo después de que finalizó la animación de selección / cancelación, pero esto produce un artefacto feo.

¿Qué debo hacer para corregir esto? ¿No inserto la subvista en el lugar correcto?

(No hay nada especial en didSelectRowAtIndexPath, simplemente cambio el accesorio de la celda a una checkbox o nada, y deselecciono el actual indexPath).

UITableViewCell cambia el color de fondo de todas las vistas secundarias cuando se selecciona o resalta la celda. Puede resolver este problema anulando el color de fondo de vista de la celda de setSelected:animated y setHighlighted:animated restablecido.

En el Objetivo C:

 - (void)setSelected:(BOOL)selected animated:(BOOL)animated { UIColor *color = self.yourView.backgroundColor; [super setSelected:selected animated:animated]; if (selected){ self.yourView.backgroundColor = color; } } -(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated{ UIColor *color = self.yourView.backgroundColor; [super setHighlighted:highlighted animated:animated]; if (highlighted){ self.yourView.backgroundColor = color; } } 

En Swift 3.1:

 override func setSelected(_ selected: Bool, animated: Bool) { let color = yourView.backgroundColor super.setSelected(selected, animated: animated) if selected { yourView.backgroundColor = color } } override func setHighlighted(_ highlighted: Bool, animated: Bool) { let color = yourView.backgroundColor super.setHighlighted(highlighted, animated: animated) if highlighted { yourView.backgroundColor = color } } 

Es porque la celda de vista de tabla cambia automáticamente el color de fondo de todas las vistas dentro de la vista de contenido para el estado resaltado. Puede considerar subclasificar a UIView para dibujar su color o usar UIImageView con una imagen personalizada de 1×1 px.

Encontré una solución bastante elegante en lugar de jugar con los métodos de selección / resaltado tableViewCell. Puede crear una subclase de UIView que ignore establecer su color de fondo para borrar el color.

Swift 3/4:

 class NeverClearView: UIView { override var backgroundColor: UIColor? { didSet { if backgroundColor != nil && backgroundColor!.cgColor.alpha == 0 { backgroundColor = oldValue } } } } 

Swift 2:

 class NeverClearView: UIView { override var backgroundColor: UIColor? { didSet { if CGColorGetAlpha(backgroundColor!.CGColor) != 0 { backgroundColor = oldValue } } } } 

Versión Obj-C:

 @interface NeverClearView : UIView @end @implementation NeverClearView - (void)setBackgroundColor:(UIColor *)backgroundColor { if (CGColorGetAlpha(backgroundColor.CGColor) != 0) { [super setBackgroundColor:backgroundColor]; } } @end 

Otra forma de gestionar el problema es llenar la vista con un degradado de gráficos centrales, como:

 CAGradientLayer* gr = [CAGradientLayer layer]; gr.frame = mySubview.frame; gr.colors = [NSArray arrayWithObjects: (id)[[UIColor colorWithRed:0 green:0 blue:0 alpha:.5] CGColor] ,(id)[[UIColor colorWithRed:0 green:0 blue:0 alpha:.5] CGColor] , nil]; gr.locations = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0],[NSNumber numberWithFloat:1],nil]; [mySubview.layer insertSublayer:gr atIndex:0]; 

Para Swift 2.2 esto funciona

 cell.selectionStyle = UITableViewCellSelectionStyle.None 

y la razón es explicada por @ Andriy

Es porque la celda de vista de tabla cambia automáticamente el color de fondo de todas las vistas dentro de la vista de contenido para el estado resaltado.

Puede cell.selectionStyle = UITableViewCellSelectionStyleNone; , luego configure backgroundColor en - (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath

Inspirado por la respuesta de Yatheesha BL , creé una categoría / extensión UITableViewCell que le permite activar y desactivar esta “función” de transparencia.

Rápido

 let cell =  cell.keepSubviewBackground = true // Turn transparency "feature" off cell.keepSubviewBackground = false // Leave transparency "feature" on 

C objective

 UITableViewCell* cell =  cell.keepSubviewBackground = YES; // Turn transparency "feature" off cell.keepSubviewBackground = NO; // Leave transparency "feature" on 

KeepBackgroundCell es compatible con CocoaPods. Puedes encontrarlo en GitHub

UITableViewCell cambia el color de fondo de todas las subvistas en la selección por algún motivo.

Esto podría ayudar:

DVColorLockView

Use algo así para evitar que UITableView cambie el color de su vista durante la selección.

Inspirado por la respuesta de Yatheesha BL .

Si llama a super.setSelected (seleccionado, animado: animado), borrará todo el color de fondo que configure . Por lo tanto, no llamaremos supermétodo.

En Swift:

 override func setSelected(selected: Bool, animated: Bool) { if(selected) { contentView.backgroundColor = UIColor.red } else { contentView.backgroundColor = UIColor.white } } override func setHighlighted(highlighted: Bool, animated: Bool) { if(highlighted) { contentView.backgroundColor = UIColor.red } else { contentView.backgroundColor = UIColor.white } } 

Dibuje la vista en lugar de establecer el color de fondo

 import UIKit class CustomView: UIView { var fillColor:UIColor! convenience init(fillColor:UIColor!) { self.init() self.fillColor = fillColor } override func drawRect(rect: CGRect) { if let fillColor = fillColor { let context = UIGraphicsGetCurrentContext() CGContextSetFillColorWithColor(context, fillColor.CGColor); CGContextFillRect (context, self.bounds); } } } 

aquí está mi solución, use contentView para mostrar selectionColor, funciona perfectamente

 #import "BaseCell.h" @interface BaseCell () @property (nonatomic, strong) UIColor *color_normal; @property (nonatomic, assign) BOOL needShowSelection; @end @implementation BaseCell @synthesize color_customSelection; @synthesize color_normal; @synthesize needShowSelection; - (void)awakeFromNib { [super awakeFromNib]; [self setup]; } - (void)setup { //save normal contentView.backgroundColor self.color_normal = self.backgroundColor; if (self.color_normal == nil) { self.color_normal = [UIColor colorWithRGBHex:0xfafafa]; } self.color_customSelection = [UIColor colorWithRGBHex:0xF1F1F1]; self.accessoryView.backgroundColor = [UIColor clearColor]; if (self.selectionStyle == UITableViewCellSelectionStyleNone) { needShowSelection = NO; } else { //cancel the default selection needShowSelection = YES; self.selectionStyle = UITableViewCellSelectionStyleNone; } } /* solution is here */ - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesBegan:touches withEvent:event]; if (needShowSelection) { self.contentView.backgroundColor = self.backgroundColor = color_customSelection; } } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesCancelled:touches withEvent:event]; if (needShowSelection) { self.contentView.backgroundColor = self.backgroundColor = color_normal; } } - (void)setSelected:(BOOL)selected animated:(BOOL)animated { [super setSelected:selected animated:animated]; if (needShowSelection) { UIColor *color = selected ? color_customSelection:color_normal; self.contentView.backgroundColor = self.backgroundColor = color; } } 

Prueba el siguiente código:

 -(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated { [super setHighlighted:highlighted animated:animated]; //Set your View's Color here. } 

Basado en la respuesta de Paul Gurov implementé lo siguiente en Xamarin.iOS. Versión C #:

NeverClearView.cs

 public partial class NeverClearView : UIView { public NeverClearView(IntPtr handle) : base(handle) { } public override UIColor BackgroundColor { get { return base.BackgroundColor; } set { if (value.CGColor.Alpha == 0) return; base.BackgroundColor = value; } } } 

NeverClearView.designer.cs

 [Register("NeverClearView")] partial class NeverClearView { void ReleaseDesignerOutlets() { } } 

No olvides anular setSelected así como setHighlighted

 override func setHighlighted(highlighted: Bool, animated: Bool) { super.setHighlighted(highlighted, animated: animated) someView.backgroundColor = .myColour() } override func setSelected(selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) someView.backgroundColor = .myColour() } 

Coloque este código en su subclase de UITableViewCell

Sintaxis de Swift 3

 override func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) if(selected) { lockerSmall.backgroundColor = UIColor.init(red: 233/255, green: 106/255, blue: 49/255, alpha: 1.0) } } override func setHighlighted(_ highlighted: Bool, animated: Bool) { super.setHighlighted(highlighted, animated: animated) if(highlighted) { lockerSmall.backgroundColor = UIColor.init(red: 233/255, green: 106/255, blue: 49/255, alpha: 1.0) } } 

Esto es similar a la respuesta de Pavel Gurov, pero es más flexible ya que permite que cualquier color sea permanente.

 class PermanentBackgroundColorView: UIView { var permanentBackgroundColor: UIColor? { didSet { backgroundColor = permanentBackgroundColor } } override var backgroundColor: UIColor? { didSet { if backgroundColor != permanentBackgroundColor { backgroundColor = permanentBackgroundColor } } } } 

Agregando otra solución si está usando storyboards. Cree una subclase de UIView que no permita establecer el backgroundColor una vez que se haya configurado inicialmente.

 @interface ConstBackgroundColorView : UIView @end @implementation ConstBackgroundColorView - (void)setBackgroundColor:(UIColor *)backgroundColor { if (nil == self.backgroundColor) { [super setBackgroundColor:backgroundColor]; } } @end 

Si la solución de fondo mencionada anteriormente no está solucionando su problema, su problema puede estar en su fuente de datasource para su tableView.

Para mí, estaba creando una instancia de un objeto DataSource (llamado BoxDataSource ) para manejar los métodos delegate y dataSource tableView, así:

 //In cellForRowAtIndexPath, when setting up cell let dataSource = BoxDataSource(delegate: self) cell.tableView.dataSource = dataSource return cell 

Esto causaba que el dataSource fuera desasignado cada vez que se tocaba la celda y, por lo tanto, todos los contenidos desaparecían. La razón es, es ARC la deslocalización / recolección de basura naturaleza.

Para solucionar esto, tuve que ir a la celda personalizada, agregar una variable de origen de datos:

 //CustomCell.swift var dataSource: BoxDataSource? 

Luego, debe configurar el dataSource en la fuente dataSource de la celda que acaba de crear en cellForRow, por lo que no se desasignará con ARC.

 cell.statusDataSource = BoxAssigneeStatusDataSource(delegate: self) cell.detailsTableView.dataSource = cell.statusDataSource return cell 

Espero que ayude.

Quería mantener el comportamiento de selección predeterminado a excepción de una subvista de celda que quería ignorar el cambio automático de color de fondo. Pero también necesitaba poder cambiar el color de fondo en otros momentos.

La solución que se me ocurrió fue subclasificar a UIView por lo que ignora el ajuste del color de fondo normalmente y agrega una función separada para eludir la protección.

Swift 4

 class MyLockableColorView: UIView { func backgroundColorOverride(_ color: UIColor?) { super.backgroundColor = color } override var backgroundColor: UIColor? { set { return } get { return super.backgroundColor } } } 

Para may may case, This is the Septs para evitar obtener el color gris para todos los elementos en la celda (en caso de que esté usando una celda de vista de tabla personalizada):

  1. Establezca el estilo de selección en .none 👉 selectionStyle = .none

  2. Reemplace este método.

    func setHighlighted (_ destacado: Bool, animado: Bool)

  3. Llame al súper, para obtener el beneficio de la configuración súper.

    super.setHighlighted (resaltado, animado: animado)

  4. Haga lo que resalte la lógica que desea.

     override func setHighlighted(_ highlighted: Bool, animated: Bool) { super.setHighlighted(highlighted, animated: animated) // Your Highlighting Logic goes here... }