setNeedsLayout retransmite la celda solo después de que se ha mostrado

Tengo una vista de tabla con celdas, que a veces tienen un elemento de interfaz de usuario opcional y, a veces, hay que eliminarlo. Según el elemento, la label cambia de tamaño.

Cuando se inicializa la celda, es más estrecha de lo que será más adelante. Cuando configuro datos en la label, este código se llama desde cellForRowAtIndexPath:

 if (someFlag) { // This causes layout to be invalidated [flagIcon removeFromSuperview]; [cell setNeedsLayout]; } 

Después de eso, la celda se devuelve a la vista de tabla y se muestra. Sin embargo, la label de text en ese punto ha ajustado su ancho, pero no la altura. La altura se ajusta después de un segundo más o less, y el movimiento se ve claramente cuando todas las celdas ya se muestran.

Nota importante, esto es solo durante la creación inicial de las primeras celdas. Una vez que se reutilizan, todo está bien, ya que la vista opcional se elimina y la label ya tiene el tamaño correcto de los usos anteriores.

¿Por qué no se reestructura la célula completamente después de setNeedsLayout pero antes de que se haya mostrado? ¿No debería UIKit verificar layouts no válidos antes de mostrar?

Si lo hago

 if (someFlag) { [flagIcon removeFromSuperview]; [cell layoutIfNeeded]; } 

todo se ajusta a la vez, pero parece una forma incorrecta de escribir código, siento que me estoy perdiendo algo más.


Un poco más de código sobre cómo se crea la celda:

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { ProfileCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier]; [cell setData:model.items[indexPath.row] forMyself:YES]; return cell; } // And in ProfileCell: - (void)setData:(Entity *)data forMyself:(BOOL)forMe { self.entity = data; [self.problematicLabel setText:data.attributedBody]; // Set data in other subviews as well if (forMe) { // This causes layouts to be invalidated, and problematicLabel should resize [self.reportButton removeFromSuperview]; [self layoutIfNeeded]; } } 

Además, si es importante, en la celda de storyboard se ve así, con la restricción opcional asumiendo el control una vez que se elimina el ícono de bandera: Limitaciones en el guión gráfico

Acepto que llamar a layoutIfNeeded parece incorrecto, aunque funciona en su caso. Pero dudo que te estés perdiendo algo. Aunque no he hecho ninguna investigación sobre la forma, en mi experiencia el uso del layout automático en celdas de tabla que se someten a un layout dynamic es un poco cochambroso. Es decir, veo los layouts entrecortados de Herky al eliminar o agregar subvistas a las celdas en time de ejecución.

Si está buscando una estrategia alternativa (utilizando el Diseño automático), puede subclass UITableViewCell y anular las layoutSubviews . La celda de tabla personalizada podría exponer un indicador en su API pública que podría configurarse en la implementación de tableView:cellForRowAtIndexPath: El método layoutSubviews la celda usaría el indicador para determinar si debería o no include el elemento de interfaz de usuario opcional. No garantizo que esto elimine el problema.

Una segunda estrategia es diseñar dos types de celdas separadas e intercambiar entre los dos en tableView:cellForRowAtIndexPath: según sea necesario.

Agregaste código adicional a la pregunta, así que tengo otra sugerencia. En el método setData:forMyself: , intente llamar a setNeedsUpdateConstraints lugar de layoutIfNeeded .