2011-03-07 13 views
58

Tengo una compilación tableViewCell simple en el constructor de interfaz. Contiene una UIView que contiene una imagen. Ahora, cuando selecciono la celda, se muestra el fondo de selección azul predeterminado, pero el color de fondo de mi UIView se ha ido.UIView backgroundColor desaparece cuando se selecciona UITableViewCell

El archivo de implementación de mi UITableViewCell no hace nada especial. Simplemente init & devuelve self y todo lo que hago en setSelected es call super.

¿Cómo puedo mostrar mi UIView backgroundColor cuando se selecciona tableView?

+0

¿Qué otros elementos de la interfaz están dentro de la vista, que quedan cubiertos por el color de selección celular? – hennes

+0

Actualmente es solo una imagen. Está destinado a hacer que la imagen se vea como una fotografía. Más adelante, agregaré una etiqueta allí también. – P5ycH0

Respuesta

96

El problema aquí es que el [muy] implementación de

- (void) setSelected:(BOOL) selected animated:(BOOL) animated; 

conjuntos de todos los colores de fondo en la UITableViewCell a RGBA (0,0,0,0). ¿Por qué? ¿Quizás para hacernos sudar a todos?

No es que vistas enteras desaparecer (como se evidencia por el hecho de que si cambia las propiedades de borde de capa de puntos de vista, los son retenidas)

Aquí es la secuencia de llamadas de función que resulta del contacto con una célula

  1. setHighlighted
  2. touchesEnded
  3. layoutSubviews
  4. willSelectRowAtIndexPath (lado delegado)
  5. setSelected (!!!aquí es donde todos los colores de fondo de la vista se les dice a desaparecer)
  6. didSelectRowAtIndexPath (lado delegado)
  7. setSelected (de nuevo) (Curiosamente colores de fondo no se borran en esta llamada. Lo extraño está pasando dentro de ese método súper?)
  8. layoutSubviews (de nuevo)

Así que sus opciones son

  1. Anulación - (void) setSelected: (BOOL) seleccionado animada: (BOOL) ani emparejado; sin llamar [super setSeleccionado: seleccionado animado: animado]. Esto le dará la implementación más correcta técnicamente porque a) el código está envuelto dentro de la subclase UITableViewCell yb) porque solo se llama cuando es necesario (bien dos veces cuando es necesario, pero tal vez hay una forma de evitarlo). El inconveniente es que tendrá que volver a implementar todas las funciones necesarias (a diferencia de las funciones innecesarias de borrado de color) de setSelected. Ahora no me pregunte cómo anular adecuadamente setSelected por el momento. Tu suposición es tan buena como la mía por ahora (ten paciencia, voy a editar esta respuesta una vez que la encuentre).
  2. Vuelva a afirmar los colores de fondo en didSelectRowAtIndexPath. Esto no es tan bueno porque coloca lo que debería ser código de instancia fuera de la instancia. Tiene la ventaja de que solo se llama cuando es necesario, a diferencia de ...
  3. Vuelva a afirmar los colores de fondo en layoutSubviews. ¡Esto no es genial en absoluto porque layoutSubviews se llama como A MILLION veces! Se llama cada vez que la mesa se actualiza, cada vez que se desplaza, cada vez que su abuela obtiene una permanente ... como en serio, un millón de veces. Eso significa que hay muchas reafirmaciones de fondo innecesarias y una gran cantidad adicional de procesamiento adicional. En el lado positivo, coloca el código dentro de la subclase UITableViewCell, lo cual es bueno.

Desafortunadamente reafirmando los colores de fondo en setHighlighted no hace nada porque setHighlighted se llama antes de que todos los colores de fondo consiguen el sistema de [r: 0 B: 0 g: 0 a: 0] por la primera llamada a setSelected.

// TODO: Dé un gran descripción de cómo anular setSelected (estad atentos)

+1

Gran respuesta. ¡Tiene mucho sentido!. Me mantendré atento a la anulación ;-) – P5ycH0

+0

Solo un seguimiento. Me he equivocado un poco con esto, pero todavía no he encontrado lo que llamaría una solución limpia y genérica para anular setSelected. Si/cuando lo haga, publicaré más información ... Feliz codificación – Brooks

+0

¡Gracias por alegrar un día que, de otro modo, sería estresante! – amcc

0

A partir de eso, dijo que construyó un tableViewCell utilizando IB, me gustaría comprobar si está agregando su vista como una subvista de contentView de UITableViewCell, no view. La vista de contenido es la supervista predeterminada para el contenido que muestra la celda.

De la referencia:

la vista del contenido de un objeto de UITableViewCell es el supervista predeterminado de contenido que se muestra por la célula. Si desea personalizar las celdas simplemente agregando vistas adicionales, debe agregarlas a la vista de contenido para que se ubiquen apropiadamente a medida que la celda ingresa y sale del modo de edición.

+0

Mi vista Hierachie en InterfaceBuilders UITableViewCell es TableViewCell> Ver> ImageView. Si estuviera compilando tableViewCell con código, podría haber agregado erróneamente mi vista a la vista de tableViewcell en lugar de a contentView, pero no veo cómo podría cometer ese error en IB ... Tenga en cuenta que mi imagen se muestra, pero el elemento de vista principal no. – P5ycH0

3

Ok, perder el color de fondo de una clase UIView es un comportamiento normal cuando está en una tabla vista seleccionada. No pude encontrar la manera de prevenir eso. Ahora acabo de reemplazar el UIView con un UIImageView que contiene un píxel blanco 1x1 estirado. Ugly imo, pero funciona.

0

Puede cambiar el comportamiento de tableViewCell anulando la función establecidaHighlighted en la clase UITableViewCell (deberá heredar de ella). Ejemplo de mi código donde puedo cambiar la imagen de fondo de la celda:

// animate between regular and highlighted state 
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated; { 
    [super setHighlighted:highlighted animated:animated]; 

    //Set the correct background Image 
    UIImageView* backgroundPicture = (UIImageView*)[self viewWithTag:HACK_BACKGROUND_VIEW_TAG]; 
    if (highlighted) { 
     backgroundPicture.image = [UIImage imageNamed:@"FondSelected.png"]; 
    } 
    else { 
     backgroundPicture.image = [UIImage imageNamed:@"Fond.png"]; 
    } 
} 

También puede cambiar el modo de selección a gris, azul o ninguno en el constructor de interfaces.

+0

Sí, lo sé. pero ese no era el problema que tenía. Me preguntaba si podría evitar perder el color de fondo de un elemento basado en UIView cuando está en una tabla vista seleccionada. Encontré una solución mediante el uso de una vista de imagen en lugar de una vista. – P5ycH0

+0

Aún más información: en mi última prueba mostré que los colores de fondo se borran CADA vez que se selecciona una celda, no solo después de la inicialización o lo que sea. La secuencia de eventos parece ser 1) setHighlighted called 2) toquesEnded llamado 3) layoutSubviews llamado 4) didSelectRowAtIndexPath llamado 4) layoutSubviews llamado de nuevo. Los colores de fondo parecen borrarse justo antes de SelectLowAtIndexPath – Brooks

4

Brooks tiene una gran explicación de por qué sucede esto, pero creo que tengo una mejor solución.

En su subvista, anule setBackgroundColor: a cualquier color que desee. Todavía se llamará al colocador, pero solo se aplicará el color especificado.

- (void)setBackgroundColor:(UIColor *)backgroundColor { 
    [super setBackgroundColor:[UIColor whiteColor]]; 
} 
12

Anteriormente he hecho como dijo @ P5ycH0 (imagen 1x1 estira), pero a raíz de @Brooks que pensé que anulando -(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated en mi implementación personalizada UITableViewCell y restablecer los los colores de fondo después de llamar a mis [super setHighlighted:highlighted animated:animated]; mantiene los colores de fondo cuando el célula se selecciona/destacó

-(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated { 
    [super setHighlighted:highlighted animated:animated]; 
    myView.backgroundColor = myColor; 
} 
+0

Esto me sirvió de algo. –

+1

Mejor solución –

+0

Gracias lo estaba buscando por 2 días – sanjeev

2

necesita anular los siguientes dos métodos en su celda personalizado:

- (void) setSelected:(BOOL)selected animated:(BOOL)animated; 
- (void) setHighlighted:(BOOL)highlighted animated:(BOOL)animated; 

Tenga en cuenta que:

  • debe llamar [super setSelected:animated:] y [super setHighlighted:animated:] en el comienzo de su aplicación personalizada o correspondencia métodos;
  • debe establecer UITableViewCellSelectionStyleNone selectionStyle para su celda personalizada, para deshabilitar cualquier estilo predeterminado UITableViewCell;

Aquí el ejemplo de la aplicación:

- (void) setHighlighted:(BOOL)highlighted animated:(BOOL)animated 
{ 
    [super setHighlighted:highlighted animated:animated]; 
    [self setHighlightedSelected:highlighted animated:animated]; 
} 

- (void) setSelected:(BOOL)selected animated:(BOOL)animated 
{ 
    [super setSelected:selected animated:animated]; 
    [self setHighlightedSelected:selected animated:animated]; 
} 

- (void) setHighlightedSelected:(BOOL)selected animated:(BOOL)animated 
{ 
    void(^selection_block)(void) = 
    ^
    { 
     self.contentView.backgroundColor = selected ? SELECTED_BACKGROUND_COLOR : NORMAL_BACKGROUND_COLOR; 
    }; 

    if(animated) 
    { 
     [UIView animateWithDuration:SELECTION_ANIMATION_DURATION 
           delay:0.0 
          options:UIViewAnimationOptionBeginFromCurrentState 
         animations:selection_block 
         completion:NULL]; 
    } 
    else 
     selection_block(); 
} 

El contentView es la propiedad de UITableViewCell que se apareció en iOS 7. Tenga en cuenta que puede utilizar la vista o vistas en lugar de que el hijo de su propia celda.

62
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated 
{ 
    UIColor *backgroundColor = self.channelImageView.backgroundColor; 
    [super setHighlighted:highlighted animated:animated]; 
    self.channelImageView.backgroundColor = backgroundColor; 
} 

- (void)setSelected:(BOOL)selected animated:(BOOL)animated 
{ 
    UIColor *backgroundColor = self.channelImageView.backgroundColor; 
    [super setSelected:selected animated:animated]; 
    self.channelImageView.backgroundColor = backgroundColor; 
} 
+0

Gran solución. Mucho más limpio que todas las soluciones de subclase y CALayer. – Joel

+0

Gracias! ¡Tu solución es la mejor! – Insider

+0

Esta fue la respuesta más útil para mí. [Modificado] (https://stackoverflow.com/a/45882764/991856) ligeramente para mi caso de uso (varias celdas con múltiples vistas de fondo bloqueadas), ¡pero felicitaciones por la solución de trabajo! – Yasir

0

En iOS 7, lo que funcionó para mí es para anular setSelected:animated: en el UITableViewCell subclase, pero al contrario de punta @Brooks', me llamaron [super setSelected:selected animated:animated].

- (void)setSelected:(BOOL)selected animated:(BOOL)animated 
{ 
    [super setSelected:selected animated:animated]; 

    // Reassert the background color of the color view so that it shows 
    // even when the cell is highlighted for selection. 
    self.colorView.backgroundColor = [UIColor blueColor]; 
} 

Esto me permite mantener la animación selección por defecto del sistema cuando el usuario pulsa sobre la célula, y también para anular su selección en la tabla didSelectRowAtIndexPath: vista del delegado.

0

Acabo de pasar un tiempo en este extraño problema. No quería configurar el estilo UITableViewCellSelectionStyleNone para conservar una buena animación cuando se seleccionó mi fila. Pero ninguna de las ideas sugeridas funcionó para mí: estaba intentando anular setSelected y establecer Highlighted y establecer mi subview backgroundColor allí; seguía reiniciando por iOS y sigue parpadeando (color nuevo -> color antiguo). Para mí, la solución fue bastante simple. Cuando se selecciona mi fila, se presiona otro controlador de vista, el usuario elige alguna opción en esa pantalla y se llama al delegado donde cambio el color en función de la selección del usuario. En este delegado acabo de hacer [celda setSelected: NO animated: NO] para mi celda. (Tengo UITableViewController estático y tengo salidas a las células). Probablemente puedas anular la selección de la celda en el método didSelect, pero en mi caso estoy usando segues.

1

Agregar a su UITableViewCell

override func setHighlighted(highlighted: Bool, animated: Bool) { 
    super.setHighlighted(false, animated: animated) 
    if highlighted { 
     self.backgroundColor = UIColor.blueColor() 
    }else{ 
     UIView.animateWithDuration(0.2, animations: { 
      self.backgroundColor = UIColor.clearColor() 
     }) 
    } 
} 
1

relacionada a la respuesta de @ Brooks, esto es lo que hice para hacer que funcione en Swift y iOS8/iOS9.

  • anular el setSelected y setHighlighted
  • NO llama súper
  • limpiar el contentView.backgroundColor, ya que no tiene que abarcar a todo lo ancho de la célula (es decir, accesorios).
  • Utilice el backgroundColor de la celda en sí, y configúrelo según corresponda.

    class AwesomeTableViewCell: UITableViewCell { 
    
        private struct Constants { 
    
         static var highlightedColor = UIColor.greenColor() 
         static var selectedColor = UIColor.redColor() 
    
         static let animationTime = NSTimeInterval(0.2) 
        } 
    
        override func awakeFromNib() { 
         super.awakeFromNib() 
    
         contentView.backgroundColor = UIColor.clearColor() 
         backgroundColor = AppContext.sharedInstance.theme.colors.background 
        } 
    
        override func setHighlighted(highlighted: Bool, animated: Bool) { 
         if animated { 
          UIView.animateWithDuration(Constants.animationTime, animations: {() -> Void in 
           self.setHighlighted(highlighted) 
          }) 
         } else { 
          self.setHighlighted(highlighted) 
         } 
        } 
    
        override func setSelected(selected: Bool, animated: Bool) { 
    
         if animated { 
          UIView.animateWithDuration(Constants.animationTime, animations: {() -> Void in 
           self.setSelected(selected) 
          }) 
         } else { 
          self.setSelected(selected) 
         } 
        } 
    
        private func setHighlighted(highlighted: Bool) { 
    
         backgroundColor = highlighted ? Constants.highlightedColor : UIColor.whiteColor() 
        } 
    
        private func setSelected(selected: Bool) { 
    
         backgroundColor = selected ? Constants.selectedColor : UIColor.whiteColor() 
        } 
    } 
    
12

Cuando se selecciona el UITableViewCell, hay dos estados que debe prestar atención a: Highlighted y Selected.

Por lo tanto, para los escenarios que tiene una clase de células costumbre que es subclase de UITableViewCell, puede sustituir fácilmente estos dos métodos para evitar esta situación (Swift):

class MyCell: UITableViewCell { 

    @IBOutlet var myView: UIView! 

    override func setHighlighted(highlighted: Bool, animated: Bool) { 
     let myViewBackgroundColor = myView.backgroundColor 
     super.setHighlighted(highlighted, animated: animated) 
     myView.backgroundColor = myViewBackgroundColor 
    } 

    override func setSelected(selected: Bool, animated: Bool) { 
     let myViewBackgroundColor = myView.backgroundColor 
     super.setSelected(selected, animated: animated) 
     myView.backgroundColor = myViewBackgroundColor 
    } 

} 
+0

la mejor respuesta para swift – sleepwalkerfx

0

Aquí está mi opinión sobre ella. Tengo una subclase que toda mi celular hereda de, por lo que es la forma en que lo hago para evitar el cambio de fondo en mis UIImageViews:

override func setHighlighted(highlighted: Bool, animated: Bool) { 
    var backgroundColors = [UIView: UIColor]() 

    for view in contentView.subviews as [UIView] { 
     if let imageView = view as? UIImageView { 
      backgroundColors[imageView] = imageView.backgroundColor 
     } 
    } 

    super.setHighlighted(highlighted, animated: animated) 

    for view in contentView.subviews as [UIView] { 
     if let imageView = view as? UIImageView { 
      imageView.backgroundColor = backgroundColors[imageView] 
     } 
    } 
} 

override func setSelected(selected: Bool, animated: Bool) { 
    var backgroundColors = [UIView: UIColor]() 

    for view in contentView.subviews as [UIView] { 
     if let imageView = view as? UIImageView { 
      backgroundColors[imageView] = imageView.backgroundColor 
     } 
    } 

    super.setSelected(selected, animated: animated) 

    for view in contentView.subviews as [UIView] { 
     if let imageView = view as? UIImageView { 
      imageView.backgroundColor = backgroundColors[imageView] 
     } 
    } 
} 

esta revisión automaticlly el problema para todos UIImageView.

0

Resumen

de este permita que la solución se bloquear algunos de los colores de fondo de una celda, mientras que el resto son controlados por el comportamiento del sistema.


Basado en mientus' answer, que han creado una solución que le permite especificar qué vistas deben mantener su color de fondo.

Esto todavía permite que otras subvistas de celda tengan su fondo eliminado al resaltar/seleccionar, y es la única solución que funciona en nuestro caso (dos vistas que necesitan un fondo permanente).

he utilizado un enfoque orientado al protocolo, con un protocolo de BackgroundLockable que contiene la lista de vistas para bloquear, y corriendo un cierre, manteniendo los colores:

protocol BackgroundLockable { 
    var lockedBackgroundViews: [UIView] { get } 
    func performActionWithLockedViews(_ action: @escaping() -> Void) 
} 

extension BackgroundLockable { 
    func performActionWithLockedViews(_ action: @escaping() -> Void) { 
     let lockedViewToColorMap = lockedBackgroundViews.reduce([:]) { (partialResult, view) -> [UIView: UIColor?] in 
      var mutableResult = partialResult 
      mutableResult[view] = view.backgroundColor 
      return mutableResult 
     } 

     action() 

     lockedViewToColorMap.forEach { (view: UIView, color: UIColor?) in 
      view.backgroundColor = color 
     } 
    } 
} 

entonces tengo una subclase de UITableViewCell, que anula destacando y selección para ejecutar el cierre del protocolo de ahí llamando el comportamiento por defecto (super):

class LockableBackgroundTableViewCell: UITableViewCell, BackgroundLockable { 

    var lockedBackgroundViews: [UIView] { 
     return [] 
    } 

    override func setHighlighted(_ highlighted: Bool, animated: Bool) { 
     performActionWithLockedViews { 
      super.setHighlighted(highlighted, animated: animated) 
     } 
    } 

    override func setSelected(_ selected: Bool, animated: Bool) { 
     performActionWithLockedViews { 
      super.setSelected(selected, animated: animated) 
     } 
    } 
} 

Ahora sólo tienen que subclase LockableBackgroundTableViewCell o utilizar el proto BackgroundLockable col en una clase de celda para agregar fácilmente el comportamiento de bloqueo a algunas celdas!

class SomeCell: LockableBackgroundTableViewCell { 

    @IBOutlet weak var label: UILabel! 
    @IBOutlet weak var icon: UIImageView! 
    @IBOutlet weak var button: UIButton! 

    override var lockedBackgroundViews: [UIView] { 
     return [label, icon] 
    } 
} 
0

Swift 4

En su UITableViewCell clase:

override func setSelected(_ selected: Bool, animated: Bool) { 
    myView.backgroundColor = UIColor.blue 
} 

override func setHighlighted(_ highlighted: Bool, animated: Bool) { 
    myView.backgroundColor = UIColor.blue 
} 
Cuestiones relacionadas