ios objective-c uitableview ios7

UITableViewCell Separator desapareciendo en iOS7



objective-c (30)

Una solución simple y limpia que funciona tanto en iOS 8 como en iOS 9 (beta 1)

Aquí hay una solución simple, limpia y no intrusiva. Implica llamar a un método de categoría que arreglará los separadores.

Todo lo que necesita hacer es caminar por la jerarquía de la celda y ocultar el separador. Me gusta esto:

for (UIView *subview in cell.contentView.superview.subviews) { if ([NSStringFromClass(subview.class) hasSuffix:@"SeparatorView"]) { subview.hidden = NO; } }

Lo que recomiendo es agregar esto a una categoría en UITableViewCell, así:

@interface UITableViewCell (fixSeparator) - (void)fixSeparator; @end @implementation UITableViewCell (fixSeparator) - (void)fixSeparator { for (UIView *subview in self.contentView.superview.subviews) { if ([NSStringFromClass(subview.class) hasSuffix:@"SeparatorView"]) { subview.hidden = NO; } } } @end

Debido a que el separador puede desaparecer en una celda diferente de la seleccionada actualmente, probablemente sea una buena idea llamar a esta corrección en todas las celdas en la vista de tabla. Para eso, puede agregar una categoría a UITableView que sea así:

@implementation UITableView (fixSeparators) - (void)fixSeparators { for (UITableViewCell *cell in self.visibleCells) { [cell fixSeparator]; } } @end

Con esto en su lugar, puede llamar -fixSeparatos en su tablaView justo después de la acción que hace que desaparezcan. En mi caso, fue después de llamar a [tableView beginUpdates] y [tableView endUpdates] .

Como dije al principio, he probado esto tanto en iOS 8 como en iOS 9. Supongo que funcionará incluso en iOS 7, pero no tengo forma de probarlo allí. Como seguramente sabrá, esto afecta las partes internas de la célula, por lo que podría dejar de funcionar en futuras versiones. Y Apple podría teóricamente (0,001% de probabilidad) rechazar tu aplicación debido a esto, pero no veo cómo podrían descubrir lo que estás haciendo allí (el hecho de comprobar el sufijo de una clase no puede ser detectado por analizadores estáticos como algo malo, IMO).

Tengo un problema extraño con UITableView solo en iOS 7.

UITableViewCellSeparator desaparece por encima de la primera fila y debajo de la última fila. A veces, después de seleccionar las filas o algunas acciones de desplazamiento aparece.

En mi caso, tableView se carga desde Storyboard con el estilo UITableViewStylePlain . El problema seguramente no está en UITableViewCellSeparatorStyle , que no se cambia del valor predeterminado UITableViewCellSeparatorStyleSingleLine .

Mientras leo en los foros de Apple Dev ( here y here ) otras personas tienen ese problema y se encuentran algunas soluciones, por ejemplo:

Workaround: disable the default selection and recreate the behaviour in a method trigged by a tapGestureRecognizer.

Pero todavía estoy buscando la razón de tal comportamiento extraño separador.

¿Algunas ideas?

Actualización: como vi en XCode 5.1 DP y iOS 7.1 beta, Apple intentó solucionar este problema. Ahora el separador se muestra, según sea necesario, a veces debajo de la última fila, después de algunas refrescantes, pero no después de la creación de tablas.


¿Intentó agregar un UIView de altura 1 en el encabezado y el pie de página de la mesa con un fondo de color gris claro? Básicamente se burlará de los primeros y últimos separadores.


@samvermette

Solucioné el problema usando estos métodos delegados. Ahora no parpadea:

-(void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { // fix for separators bug in iOS 7 tableView.separatorStyle = UITableViewCellSeparatorStyleNone; tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine; } -(void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { // fix for separators bug in iOS 7 tableView.separatorStyle = UITableViewCellSeparatorStyleNone; tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine; }


Aquí está mi solución a este problema. Después de insertar su (s) celda (s), vuelva a cargar la sección. Si volver a cargar toda la sección es demasiado intenso para usted, simplemente vuelva a cargar IndexPaths arriba y abajo.

[CATransaction begin]; [CATransaction setCompletionBlock:^{ // Fix for issue where seperators disappear [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone]; }]; [self.tableView insertRowsAtIndexPaths:@[ indexPath ] withRowAnimation:UITableViewRowAnimationFade]; [CATransaction commit];


Aquí hay una solución más fácil (aunque un poco desordenada) si la necesita, intente seleccionar y anular la selección de la celda después de que los datos se vuelvan a cargar y se complete la animación predeterminada.

solo agrega:

[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone]; [self.tableView deselectRowAtIndexPath:indexPath animated:NO];


Basado en el comentario de @ ortwin-gentz, esta solución funciona para mí en iOS 9.

func fixCellsSeparator() { // Loop through every cell in the tableview for cell: UITableViewCell in self.tableView.visibleCells { // Loop through every subview in the cell which its class is kind of SeparatorView for subview: UIView in (cell.contentView.superview?.subviews)! where NSStringFromClass(subview.classForCoder).hasSuffix("SeparatorView") { subview.hidden = false } } }

(Código SWIFT)

Utilizo la función fixCellsSeparator () después de llamar a endUpdates () en algunos métodos de mi tableView, por ejemplo:

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { // Perform some stuff // ... self.tableView.endUpdates() self.fixCellsSeparator() }

¡Espero que esta solución sea útil para alguien!


Como alguien más mencionó, este problema parece manifestarse en una variedad de formas. Resolví mi problema a través de la siguiente solución alternativa:

[tableView beginUpdates]; [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; [tableView endUpdates];


Como este sigue siendo un problema con IOS 8, agregaré mi solución en Swift. Establezca la línea del separador de tablas en ninguna. A continuación, agregue este código al método de delegado cellForRowAtIndexPath. Se agregará un buen separador. La instrucción if permite decidir qué celdas deben tener un separador.

var separator:UIView! if let s = cell.viewWithTag(1000) { separator = s } else { separator = UIView() separator.tag = 1000 separator.setTranslatesAutoresizingMaskIntoConstraints(false) cell.addSubview(separator) // Swiper constraints var leadingConstraint = NSLayoutConstraint(item: separator, attribute: .Leading, relatedBy: .Equal, toItem: cell, attribute: .Leading, multiplier: 1, constant: 15) var heightConstraint = NSLayoutConstraint(item: separator, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 0.5) var bottomConstraint = NSLayoutConstraint(item: cell, attribute: .Bottom, relatedBy: .Equal, toItem: separator, attribute: .Bottom, multiplier: 1, constant:0) var trailingConstraint = NSLayoutConstraint(item: cell, attribute: .Trailing, relatedBy: .Equal, toItem: separator, attribute: .Trailing, multiplier: 1, constant: 15) cell.addConstraints([bottomConstraint, leadingConstraint, heightConstraint, trailingConstraint]) } if indexPath.row == 3 { separator.backgroundColor = UIColor.clearColor() } else { separator.backgroundColor = UIColor.blackColor() }


Complemento a la respuesta de airpaulg.

Entonces, básicamente, uno tiene que implementar dos métodos UITableDelegate. Aquí está mi solución que funciona tanto en iOS7 como en iOS6.

#define IS_OS_VERSION_7 (NSFoundationVersionNumber_iOS_6_1 < floor(NSFoundationVersionNumber)) #define UIColorFromRGB(hexRGBValue) [UIColor colorWithRed:((float)((hexRGBValue & 0xFF0000) >> 16))/255.0 green:((float)((hexRGBValue & 0xFF00) >> 8))/255.0 blue:((float)(hexRGBValue & 0xFF))/255.0 alpha:1.0]

// Esto ocultará la cuadrícula de la tabla vacía debajo de las celdas si no cubren toda la pantalla

- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section { UIView *view = nil; if (IS_OS_VERSION_7 /* && <is this the last section of the data source> */) { CGFloat height = 1 / [UIScreen mainScreen].scale; view = [[UIView alloc] initWithFrame:CGRectMake(0., 0., 320., height)]; view.backgroundColor = UIColorFromRGB(0xC8C7CC); view.autoresizingMask = UIViewAutoresizingFlexibleWidth; } else { view = [UIView new]; } return view; } - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { if (IS_OS_VERSION_7 /* && <is this the last section of the data source> */) { return 1 / [UIScreen mainScreen].scale; } else { // This will hide the empty table grid below the cells if they do not cover the entire screen return 0.01f; } }


Configurar el estilo en viewWillAppear funcionó para mí.


Debe eliminar una selección de celda antes de hacer la actualización de la celda. Entonces podrías restaurar la selección.

NSIndexPath *selectedPath = [self.tableview indexPathForSelectedRow]; [self.tableview deselectRowAtIndexPath:selectedPath animated:NO]; [self.tableview reloadRowsAtIndexPaths:@[ path ] withRowAnimation:UITableViewRowAnimationNone]; [self.tableview selectRowAtIndexPath:selectedPath animated:NO scrollPosition:UITableViewScrollPositionNone];


Descarté la jerarquía de la subvista de las celdas afectadas y encontré que _UITableViewCellSeparatorView estaba configurado como oculto. ¡No me sorprende que no se muestre!

layoutSubviews en mi subclase UITableViewCell y ahora los separadores se muestran de forma confiable:

Objective-C :

- (void)layoutSubviews { [super layoutSubviews]; for (UIView *subview in self.contentView.superview.subviews) { if ([NSStringFromClass(subview.class) hasSuffix:@"SeparatorView"]) { subview.hidden = NO; } } }

Swift :

override func layoutSubviews() { super.layoutSubviews() guard let superview = contentView.superview else { return } for subview in superview.subviews { if String(subview.dynamicType).hasSuffix("SeparatorView") { subview.hidden = false } } }

Las otras soluciones propuestas aquí no funcionaron consistentemente para mí o parecen torpes (agregando vistas personalizadas de 1 px de pie de página).


Descubrí que la solución más fácil es, después de volver a cargar una celda, también volver a cargar la celda anterior:

if (indexPath.row > 0) { NSIndexPath *path = [NSIndexPath indexPathForRow:indexPath.row - 1 inSection:indexPath.section]; [self.tableView reloadRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationNone]; }


En su Subescala UITableViewCell, implemente layoutSubviews y agregue:

- (void)layoutSubviews{ [super layoutSubviews] for (UIView *subview in self.contentView.superview.subviews) { if ([NSStringFromClass(subview.class) hasSuffix:@"SeparatorView"]) { CGRect separatorFrame = subview.frame; separatorFrame.size.width = self.frame.size.width; subview.frame = separatorFrame; } } }


Esto funcionó para mí:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // fix for separators bug in iOS 7 self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;


Esto solucionó el problema para mí:

Asegúrese de que clipsToBounds esté establecido en SÍ para la celda, pero NO para el contenido de la celda. También configure cell.contentView.backgroundColor = [UIColor clearColor];


He resuelto poner estas líneas de código donde se abre la actualización de la tabla:

self.tableView.separatorStyle = UITableViewCellSeparatorStyle.None; self.tableView.separatorStyle = UITableViewCellSeparatorStyle.SingleLine;

Por ejemplo, en mi caso los he puesto aquí:

tableView.beginUpdates() tableView.insertRowsAtIndexPaths(insertIndexPaths, withRowAnimation: UITableViewRowAnimation.Fade) tableView.endUpdates() self.tableView.separatorStyle = UITableViewCellSeparatorStyle.None; self.tableView.separatorStyle = UITableViewCellSeparatorStyle.SingleLine;


Intenté muchas sugerencias para solucionar, pero no puedo solucionarlo. Finalmente, decidí personalizar la línea de separación de la siguiente manera:

func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) { var lineView = UIView(frame: CGRectMake(20, cell.contentView.frame.size.height - 1.0, cell.contentView.frame.size.width - 20, 1)) lineView.backgroundColor = UIColor(red: 170.0/255.0, green: 170.0/255.0, blue: 170.0/255.0, alpha: 1) cell.contentView.addSubview(lineView) }

P / S: personalizado en willDisplayCell NOT cellForRowAtIndexPath


Lo que hizo la diferencia para mí fue volver a cargar la fila para la que no aparecería la línea del separador inferior:

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:rowIndex inSection:sectionIndex]; [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];


Nos encontramos con este problema en nuestra aplicación. Cuando el usuario seleccionaba una celda, se colocaba una nueva vista de tabla en la pila del controlador de navegación y luego, cuando el usuario la desconectaba, faltaba el separador. Lo solucionamos poniendo [self.tableView deselectRowAtIndexPath:indexPath animated:NO]; en el método de delegado de vista de tabla didSelectRowAtIndexPath .


Para solucionar el problema anterior, agregue el pie de página vacío en viewDidLoad.

UIView *emptyView_ = [[UIView alloc] initWithFrame:CGRectZero]; emptyView_.backgroundColor = [UIColor clearColor]; [tableView setTableFooterView:emptyView_];

No utilice las líneas anteriores en el método de delegado viewForFooterInSection. Significa No implementar el método viewForFooterInSection.


Parece que este problema se manifiesta bajo tantas circunstancias.

Para mí, tenía algo que ver con la selección de células. No tengo idea de por qué y no tuve tiempo para profundizar demasiado, pero puedo decir que comenzó a ocurrir cuando establecí el estilo de selectionStyle la celda en ninguno. es decir:

//This line brought up the issue for me cell.selectionStyle = UITableViewCellSelectionStyleNone;

Intenté usar algunos de los métodos de delegado anteriores que activan y desactivan la propiedad separatorStyle de tableView pero no parecían hacer nada para solucionar mi problema.

Todo el motivo por el que lo necesitaba era porque ni siquiera necesitaba la selección de células.

Entonces, encontré algo que funcionó para mí. Acabo de desactivar la selección en la UITableView :

tableView.allowsSelection = NO;

Espero que esto ayude a alguien, si no necesita tener una selección de celda.


Pasando por las respuestas y las soluciones, surgieron tales observaciones:

Esto parece ser problemático tanto en iOS 7 como en 8. Me di cuenta del problema al seleccionar la celda del código en el método viewDidLoad así:

1) la solución lo estaba haciendo en viewDidAppear: si a alguien no le importa el retraso notable entre la presentación de la vista y la selección de la celda

2) la segunda solución funcionó para mí, pero el código parece un poco frágil ya que se basa en la implementación interna de UITableViewCell

3) agregar el propio separador parece ser el más flexible y el mejor por ahora pero requiere más codificación :)


Resuelvo este problema de otra manera: agregue una capa que tenga una altura de 0.5 px y su color sea gris claro en tableview.tableFooterView como su subcapa.

el código es así:

UIView *tableFooterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 70)]; CALayer *topSeperatorLine = [CALayer layer]; topSeperatorLine.borderWidth = 0.5f; topSeperatorLine.borderColor = [UIColor lightGrayColor].CGColor; topSeperatorLine.frame = CGRectMake(0, 0, 320, 0.5f); [tableFooterView.layer addSublayer:topSeperatorLine]; self.tableView.tableFooterView = tableFooterView;


Sorprendentemente, cambiar el valor del conjunto separatorInset la celda de ida y vuelta parece estar funcionando:

NSIndexPath *selectedPath = [self.controller.tableView indexPathForSelectedRow]; [self.controller.tableView deselectRowAtIndexPath:selectedPath animated:YES]; UITableViewCell *cell = [self.controller.tableView cellForRowAtIndexPath:selectedPath]; UIEdgeInsets insets = cell.separatorInset; cell.separatorInset = UIEdgeInsetsMake(0.0, insets.left + 1.0, 0.0, 0.0); cell.separatorInset = insets;


También encontré este problema en nuestro proyecto. Mi vista de tabla tenía un tableFooterView que podría hacer que esto suceda. Encontré que el separador debajo de la última fila aparecería si eliminé esa tabla FooterView.


También tuve el problema con el separador faltante y descubrí que el problema solo heightForRowAtIndexPath cuando heightForRowAtIndexPath devolvía un número decimal . Solución:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { return ceil(yourHeight) // Ceiling this value fixes disappearing separators }


También tuve el problema de esta visualización irregular de la línea separadora en la parte inferior de mi UITableView. Utilizando una vista de pie de página personalizada, he podido crear una línea similar y mostrarla sobre la posible existente (que a veces faltaba).

El único problema de esta solución es que Apple puede cambiar un día el grosor de la línea

- (UIView*) tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section { float w = tableView.frame.size.width; UIView * footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, w, 1)]; footerView.autoresizingMask = UIViewAutoresizingFlexibleWidth; footerView.clipsToBounds=NO; UIView* separatoraddon = [[UIView alloc] initWithFrame:CGRectMake(0, -.5, w, .5)]; separatoraddon.autoresizingMask = UIViewAutoresizingFlexibleWidth; separatoraddon.backgroundColor = tableView.separatorColor; [footerView addSubview:separatoraddon]; return footerView; } - (CGFloat) tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { return 1; }


encontré con un problema similar, encontré que otra buena solución, especialmente si su dataSource no es grande, vuelve a cargar tableData cuando implementa el método -(void)scrollViewDidScroll:(UIScrollView *)scrollView , aquí hay un ejemplo:

-(void)scrollViewDidScroll:(UIScrollView *)scrollView { if (scrollView == self.tableView1) { [self.tableView1 reloadData]; } else { [self.tableView2 reloadData]; } }

También puede simplemente volver a cargar datos no visibles en función de la fuente de datos visible, pero eso requiere más piratería.

¡Tenga en cuenta que esta función de delegado se encuentra bajo el protocolo UITableViewDelegate !

¡Espero eso ayude!


expandir la respuesta de airpaulg, porque no me funcionó del todo ...

también tuve que implementar el método heightforfooter para obtener la altura

entonces noté que el color claro de la luz es demasiado oscuro. Lo solucioné agarrando el color del separador actual de la tabla vista y usando eso:

UIColor *separatorGray = [self.briefcaseTableView separatorColor]; [footerSeparator setBackgroundColor:separatorGray];