ios - custom - UITableview agrupada elimina la línea de separación exterior
uitableviewcell (15)
Tengo una UITableview agrupada que se crea mediante programación. También tengo una celda con el archivo xib poblado en tableview también mediante programación. Hasta aquí todo bien. Pero solo quiero eliminar la línea de separación exterior. Usé el siguiente código, pero esta vez eliminé toda la línea de separación.
self.tableView.separatorColor = [UIColor clearColor];
Esta no es una buena opción para mi situación. Aquí está la captura de pantalla de lo que quiero hacer;
Acabo de encontrar una solución, ya que la celda tiene
contentView
que es una
UIView
, por lo que creo que puede centrarse en la línea inferior de
contentView
.
Aquí está mi código:
primero, tienes que hacer el separador para borrar
tableView.separatorColor = UIColor.clear
En segundo lugar, en la función
cellForRowAt
:
let bottomBorder = CALayer()
bottomBorder.frame = CGRect(x: 0.0, y: 43.0, width: cell.contentView.frame.size.width, height: 1.0)
bottomBorder.backgroundColor = UIColor(white: 0.8, alpha: 1.0).cgColor
cell.contentView.layer.addSublayer(bottomBorder)
aquí verás la interfaz de usuario así:
Aquí hay una solución Swift que funciona en iOS 8 y 9.
Defina un protocolo con una implementación predeterminada:
protocol CellSeparatorRemovable { }
extension CellSeparatorRemovable {
func removeSeparatorLinesFromCell(cell: UITableViewCell, section: Int, row: Int, indexPath: NSIndexPath) {
guard (section, row) == (indexPath.section, indexPath.row) else { return }
for view in cell.subviews where view != cell.contentView {
view.removeFromSuperview()
}
}
}
Luego, donde quiera usarlo, cumpla con el protocolo
CellSeparatorRemovable
y llame a su método desde
…willDisplayCell…
:
class SomeVC: UITableViewController, CellSeparatorRemovable {
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
removeSeparatorLinesFromCell(cell, section: 1, row: 1, indexPath: indexPath)
}
}
Esta es una solución mínima; Es posible que necesite refactorizarlo si está tratando con muchas celdas para evitar problemas de recidiva excesiva y / o reutilización de celdas.
Aquí la solución. Esto es para celdas estáticas. Si quieres dinámico, simplemente reescribe "contar". Espero eso ayude.
override func layoutSubviews() {
super.layoutSubviews()
//Get the width of tableview
let width = subviews[0].frame.width
for view in subviews where view != contentView {
//for top and bottom separator will be same width with the tableview width
//so we check at here and remove accordingly
if view.frame.width == width {
view.removeFromSuperview()
}
}
}
Basado en la respuesta del cocinero, pero sin temporizador:
override func didAddSubview(_ subview: UIView) {
super.didAddSubview(subview)
if NSStringFromClass(subview.classForCoder) != "UITableViewCellContentView" && subview.frame.width == frame.width {
subview.removeFromSuperview()
}
}
Simplemente agregue esto en la subclase de una celda y no necesitará nada más. Funciona en iOS 12.
Después de inspeccionar la jerarquía de vistas, parece que cada UITableViewCell tiene solo tres subvistas: la vista de contenido (
UITableViewCellContentView
) y dos vistas de separador (
_UITableViewCellSeparatorView
).
No soy fanático de la instanciación de clase dinámica de NSStrings (y tampoco lo es Apple 😉).
Sin embargo, dado que se puede
contentView
al
contentView
de un
UITableViewCell
sin utilizar API privadas, la solución resulta bastante fácil.
La idea es simplemente recorrer las subvistas de su
UITableViewCell
y eliminar cualquier vista que no sea
contentView
:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyReusableIdentifier", for: indexPath)
Timer.scheduledTimer(withTimeInterval: 0.15, repeats: false) { (timer) in
cell.removeSectionSeparators()
}
return cell
}
tableView(:willDisplayCell:forRowAtIndexPath:)
se llama varias veces durante la representación de la vista de tabla, por lo que lo anterior realiza un seguimiento del estado al verificar cuántas subvistas tiene la celda.
Si tiene tres subvistas, ambos separadores aún están intactos.
También solo elimina uno de los separadores, pero puede eliminar ambos eliminando el
break
.
También puede especificar si desea eliminar el separador superior o el separador inferior marcando el marco de la subvista.
Si el origen del eje y del cuadro es
0
, ese es el separador superior.
Si no es
0
, es la parte inferior.
¡Espero que esto ayude!
Swift 4, Swift 4.2 Actualización:
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.removeSectionSeparators()
}
Esa es una pregunta muy antigua, aún así es una de las primeras entradas en Google cuando se busca cómo eliminar los separadores superior e inferior de cada sección.
Después de un poco de investigación, descubrí que no hay forma ni solo intención de Apple de hacer que esto suceda de alguna manera sin trucos estúpidamente complicados de la jerarquía de vistas.
Afortunadamente, hay una manera absolutamente simple y fácil de lograr ese aspecto:
Digo simple, pero para un principiante, esto podría ser difícil debido a la falta de comprensión de cómo funciona
UITableView
y cómo implementar sus propias células.
Déjame intentar explicarlo:
-
Crear una subclase
UITableViewCell
-
En su celda, cree un
@IBOutlet weak var separatorView: UIView!
propiedad - En su Storyboard, seleccione la celda de vista de tabla y seleccione su propia celda como la clase que respalda la celda. Nota : No tiene que usar un estilo personalizado. Todavía puedes usar Basic, Subtitle, etc.
-
Establezca el
Separator Style
UITableView
enNone
para ocultar el separador predeterminado -
Arrastre una vista
UIView
a su celda yUIView
su tamaño para que quede en la parte inferior (o superior) de la celda. Utilice elAutoresizing
Size Inspector
Autoresizing
para fijarlo al inicio / final / inferior y darle un ancho flexible (o Autolayout, pero en este caso es un poco por encima) - Conecte la vista a la salida de su clase celular
-
En su
UITableViewDataSource
scellForRowAtIndexPath:
establezca la propiedadisHidden
de su separador personalizado en función de siindexPath.row
es la última fila (o la primera, si su vista está en la parte superior) en la sección
Aquí hay un código de ejemplo:
class MyCell: UITableViewCell {
@IBOutlet weak var separatorView: UIView!
}
class ViewController: UITableViewController {
override func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! MyCell
cell.separatorView.isHidden = indexPath.row == 2
return cell
}
}
Y aquí algunas capturas de pantalla:
Sí, es algo de trabajo, pero simplemente no hay forma de hacer algo gratis al codificar. Al final, somos programadores y depende de nosotros hacer la codificación. Siempre es mejor pasar los 5-10 minutos configurando esto que simplemente copiar y pegar un código hacky que podría no seguir funcionando en el futuro cuando Apple decida cambiar la jerarquía de vistas.
En realidad, fue más trabajo escribir esta respuesta que implementar el separador. Yo también estaba buscando una solución fácil y rápida, pero al final simplemente no había una solución suficientemente buena que valiera la pena usar.
Espero que también se sienta escéptico cuando vea bucles for iterando sobre subvistas de celdas para ocultar o incluso eliminar vistas en tiempo de ejecución de la jerarquía de vistas que Apple le proporciona, cuando hay una solución fácil, versátil, estable y a prueba de futuro a la vuelta de la esquina . 7 pequeños pasos son realmente todo lo que necesita y son fáciles de entender.
Esto es lo que finalmente se me ocurrió:
No pude encontrar una manera mejor que esta. Pero me está funcionando mucho. Última prueba con Xcode versión 7.3.1 (7D1014). Este procedimiento se realizó a través del guión gráfico.
Básicamente agrego una UIView de 0.5 pt de altura en UITableViewCell y luego establezco un color de fondo para esa UIView. Establezca el separador padre UITableView como Ninguno.
Aquí están los detalles:
Teniendo en cuenta que ya configuró su UITableViewCell, personalizado o predeterminado. En la primera etapa, establezca el separador de UITableView como Ninguno.
A continuación, agregue una vista UIView de 1 pt de altura y configure el fondo según lo necesite, en mi caso es rojo.
Comience a establecer las restricciones. El problema es establecer la altura de la UIView como 0.5 pt. Este es el único problema problemático para este flujo de trabajo.
UIView con 0.5 pt de altura:
Compartiendo la forma de establecer 0.5 pt de altura de la UIView.
Primero (1) fije la vista y luego (2) establezca la altura en 0.5. Presione Entrar.
Finalmente, su UIView se verá similar a la siguiente.
No pude establecer la altura como 0.5 aparte de esta manera.
Google, incluso en 2018, está sirviendo esta página como el mejor resultado para esta pregunta. No tuve suerte en iOS 11 con ninguna de las respuestas proporcionadas, así que esto es lo que se me ocurrió:
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
let subviews = cell.subviews
if subviews.count >= 3 {
for subview in subviews {
if subview != cell.contentView {
subview.removeFromSuperview()
break
}
}
}
}
Llamar a .removeSectionSeparators () en cualquier instancia de UITableViewCell ahora se ocupará del problema. Al menos en mi caso, los separadores de sección son los únicos con el mismo ancho que la celda en sí (ya que los otros están sangrados).
La única pregunta que queda es de dónde deberíamos llamarlo. Pensarías que willDisplayCell sería la mejor opción, pero descubrí que la llamada inicial se produce antes de que se generen las vistas del separador, por lo que no hay dados.
Terminé poniendo esto en mi método cellForRowAtIndexPath justo antes de devolver una celda recargada:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let subviews = cell.subviews
guard subviews.count >= 3 else {
return
}
for subview in subviews where NSStringFromClass(subview.classForCoder) == "_UITableViewCellSeparatorView" {
subview.removeFromSuperview()
}
}
No se siente tan elegante, pero aún no me he encontrado con ningún problema.
EDITAR: Parece que también necesitamos esto (para celdas reutilizadas):
extension UITableViewCell {
func removeSectionSeparators() {
for subview in subviews {
if subview != contentView && subview.frame.width == frame.width {
subview.removeFromSuperview()
}
}
}
}
Aquí hay un antes / después en capturas de pantalla con este código:
Intenté varias soluciones basadas en la solución
cell.separatorInset = UIEdgeInsetsMake()
, ninguna de ellas funciona correctamente.
Para mi proyecto basado en iOS11
UITableViewStyleGrouped
, esto lo hizo:
self.tableView.separatorColor = self.tableView.backgroundColor;
Para quitar la parte superior e inferior de la línea de separación para cada sección. Agregue esto a su celda estática.
extension NSObject {
var theClassName: String {
return NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last!
}
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.separatorStyle = .None
}
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
let count = tableView.numberOfRowsInSection(indexPath.section)
if ( indexPath.row != count - 1 ) {
for view in cell.subviews {
if view.theClassName == "_UITableViewCellSeparatorView" {
view.backgroundColor = UIColors.redColor()
}
}
}
}
Resultado como la imagen de abajo
Pruebe esto, eliminará la línea de separación superior.
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row == 0 && indexPath.section == 0) {
for (UIView *view in cell.subviews) {
if ([NSStringFromClass([view class]) containsString:@"CellSeparator"]) {
if (view.frame.origin.y == 0 && CGRectGetHeight(view.frame) < 1.01 ) { //Hide first UITableViewCellSeparatorView
NSLog(@"%s Remove View From Cell[Section:0 Row:0] for top border [%@]:%@",__FUNCTION__,NSStringFromClass([view class]),view);
view.hidden = YES; //Hide
}
}
}
}
}
Puede acceder a la vista usando
override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
let header = view as! UITableViewHeaderFooterView
header.backgroundView . .....
Puede eliminar separadores incluso en UITableView agrupada con celda estática:
class Cell: UITableViewCell {
override func layoutSubviews() {
super.layoutSubviews()
for view in subviews where view != contentView {
view.removeFromSuperview()
}
}
Tuve un problema similar, donde tuve un UITableView Agrupado con celdas personalizadas, todo diseñado con Interface Build como archivos .xib. Las celdas tenían fondos blancos, eliminaron los separadores predeterminados y agregaron los míos. También tenía vistas de encabezado personalizadas para cada sección. Establecí la altura de esas Vistas de encabezado en 44 (podría ser cualquier cosa ...). Había una vista de 1 punto de altura entre mis secciones, lo que parecía extraño. Aparentemente, el sistema agrega una vista de fondo clara entre las secciones, incluso si especificamos la altura personalizada, digamos 44, y la Vista de encabezado personalizada que devolvemos tiene un color blanco (o un color de fondo concreto). El color que vemos detrás de esa vista clara es el color del fondo de la Vista de tabla en realidad. En mi caso, tanto las vistas de tabla como las celdas tenían que ser de color blanco, y establecer el fondo de la vista de tabla en blanco resolvió el problema (al menos visualmente, pero eso es lo que quería de todos modos). La segunda solución sería mantener el estilo de la Vista de tabla simple, pero implementar el método de delegado UITableView para devolver 2 o más secciones, y también crear encabezados personalizados si es necesario. Pero eso hará que las vistas de encabezado se mantengan en la parte superior por un tiempo (mientras se desplaza), hasta que la vista de encabezado de la siguiente sección se acerque a ella y luego comience a subir también (y eso puede no ser lo que realmente desea, pero allí puede ser una manera fácil de arreglar eso, aunque no estoy seguro).