ios objective-c uitableview cocoa-touch separator

ios - Ocultar línea separadora en un UITableViewCell



objective-c cocoa-touch (30)

Para Swift 2:

agregue la siguiente línea a viewDidLoad() :

tableView.separatorColor = UIColor.clearColor()

Estoy personalizando un UITableView . Quiero ocultar la línea que separa en la última celda ... ¿puedo hacer esto?

Sé que puedo hacer tableView.separatorStyle = UITableViewCellStyle.None pero eso afectaría a todas las celdas de la tableView. Quiero que solo afecte a mi ultima celda.


Como (muchos) otros han señalado, puede ocultar fácilmente todos los separadores UITableViewCell simplemente desactivándolos para la propia vista de UITableView; por ejemplo, en su UITableViewController

- (void)viewDidLoad { ... self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; ... }

Desafortunadamente, es un PITA real para realizarlo por celda , que es lo que realmente estás preguntando.

Personalmente, he intentado numerosas permutaciones para cambiar cell.separatorInset.left , nuevamente, como (muchos) otros han sugerido, pero el problema es citar a Apple (énfasis agregado):

" ... Puede usar esta propiedad para agregar espacio entre el contenido de la celda actual y los bordes izquierdo y derecho de la tabla. Los valores de inserción positivos mueven el contenido de la celda y el separador de celda hacia adentro y lejos de los bordes de la tabla ... "

Así que si intentas "ocultar" el separador empujándolo fuera de la pantalla hacia la derecha, también puedes sangrar el contenido de tu celda. Como lo sugiere crifan, puedes intentar compensar este desagradable efecto secundario configurando cell.indentationWidth y cell.indentationLevel para mover todo de nuevo, pero he descubierto que esto también es poco confiable (el contenido aún está sangrado ... ).

La forma más confiable que he encontrado es layoutSubviews de las layoutSubviews en una subclase de UITableViewCell simple y configurar el recuadro derecho para que toque el recuadro izquierdo, haciendo que el separador tenga un ancho de 0 y sea tan invisible [esto debe hacerse en el diseño. maneja automáticamente las rotaciones]. También agrego un método de conveniencia a mi subclase para activar esto.

@interface MyTableViewCellSubclass() @property BOOL separatorIsHidden; @end @implementation MyTableViewCellSubclass - (void)hideSeparator { _separatorIsHidden = YES; } - (void)layoutSubviews { [super layoutSubviews]; if (_separatorIsHidden) { UIEdgeInsets inset = self.separatorInset; inset.right = self.bounds.size.width - inset.left; self.separatorInset = inset; } } @end

Advertencia: no hay una manera confiable de restaurar el recuadro original correcto, por lo que no puede ''des-ocultar'' el separador, por lo tanto, estoy usando un método hideSeparator irreversible (vs exponiendo separatorIsHidden). Tenga en cuenta que separatorInset persiste en las celdas reutilizadas, por lo que, como no puede "no ocultar", debe mantener estas celdas separadoras ocultas aisladas en su propio reuseIdentifier.


Debe tomar una celda personalizada y agregar una Etiqueta y establecer una restricción, ya que una etiqueta debe cubrir toda el área de la celda. y escribe la siguiente línea en el constructor.

- (void)awakeFromNib { // Initialization code self.separatorInset = UIEdgeInsetsMake(0, 10000, 0, 0); //self.layoutMargins = UIEdgeInsetsZero; [self setBackgroundColor:[UIColor clearColor]]; [self setSelectionStyle:UITableViewCellSelectionStyleNone]; }

También establezca el margen de diseño de UITableView como sigue

tblSignup.layoutMargins = UIEdgeInsetsZero;


En willdisplaycell :

cell.separatorInset = UIEdgeInsetsMake(0, cell.bounds.size.width, 0, 0)


En Swift 3 y Swift 4 , puede escribir una extensión para UITableViewCell como esta:

extension UITableViewCell { func hideSeparator() { self.separatorInset = UIEdgeInsets(top: 0, left: self.bounds.size.width, bottom: 0, right: 0) } func showSeparator() { self.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) } }

Luego, puede usar esto como se muestra a continuación (cuando celda es su instancia de celda):

cell.hideSeparator() cell.showSeparator()

Realmente es mejor asignar el ancho de la celda de vista de tabla como recuadro izquierdo en lugar de asignarle un número aleatorio. Debido a que en algunas dimensiones de la pantalla, puede que no ahora, pero en el futuro sus separadores aún puedan ser visibles porque ese número aleatorio puede no ser suficiente. Además, en iPad en modo horizontal no puede garantizar que sus separadores siempre serán invisibles.


En Swift usando iOS 8.4 :

/* Tells the delegate that the table view is about to draw a cell for a particular row. (optional) */ override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) { if indexPath.row == 3 { // Hiding separator line for only one specific UITableViewCell cell.separatorInset = UIEdgeInsetsMake(0, cell.bounds.size.width, 0, 0) } }

Nota: este fragmento de código anterior funcionará en UITableView utilizando celdas dinámicas. El único problema que puede encontrar es cuando usa celdas estáticas con categorías, un tipo de separador diferente a ninguno y un estilo agrupado para la vista de tabla. De hecho, en este caso particular no ocultará la última celda de cada categoría. Para superar eso, la solución que encontré fue establecer el separador de celda (a través de IB) en ninguno y luego crear y agregar manualmente (a través del código) su vista de línea a cada celda. Para un ejemplo, por favor revise el siguiente fragmento de código:

/* Tells the delegate that the table view is about to draw a cell for a particular row. (optional) */ override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) { // Row 2 at Section 2 if indexPath.row == 1 && indexPath.section == 1 { // Hiding separator line for one specific UITableViewCell cell.separatorInset = UIEdgeInsetsMake(0, cell.bounds.size.width, 0, 0) // Here we add a line at the bottom of the cell (e.g. here at the second row of the second section). let additionalSeparatorThickness = CGFloat(1) let additionalSeparator = UIView(frame: CGRectMake(0, cell.frame.size.height - additionalSeparatorThickness, cell.frame.size.width, additionalSeparatorThickness)) additionalSeparator.backgroundColor = UIColor.redColor() cell.addSubview(additionalSeparator) } }


En iOS 7, el separador de celdas de estilo agrupado UITableView se ve un poco diferente. Se ve un poco así:

Intenté la answer de Kemenaran de hacer esto:

cell.separatorInset = UIEdgeInsetsMake(0, 10000, 0, 0);

Sin embargo, eso no parece funcionar para mí. No estoy seguro de por qué. Así que decidí usar la answer de Hiren, pero usando UIView lugar de UIImageView , y dibuja la línea en el estilo de iOS 7:

UIColor iOS7LineColor = [UIColor colorWithRed:0.82f green:0.82f blue:0.82f alpha:1.0f]; //First cell in a section if (indexPath.row == 0) { UIView *line = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 1)]; line.backgroundColor = iOS7LineColor; [cell addSubview:line]; [cell bringSubviewToFront:line]; } else if (indexPath.row == [self.tableViewCellSubtitles count] - 1) { UIView *line = [[UIView alloc] initWithFrame:CGRectMake(21, 0, self.view.frame.size.width, 1)]; line.backgroundColor = iOS7LineColor; [cell addSubview:line]; [cell bringSubviewToFront:line]; UIView *lineBottom = [[UIView alloc] initWithFrame:CGRectMake(0, 43, self.view.frame.size.width, 1)]; lineBottom.backgroundColor = iOS7LineColor; [cell addSubview:lineBottom]; [cell bringSubviewToFront:lineBottom]; } else { //Last cell in the table view UIView *line = [[UIView alloc] initWithFrame:CGRectMake(21, 0, self.view.frame.size.width, 1)]; line.backgroundColor = iOS7LineColor; [cell addSubview:line]; [cell bringSubviewToFront:line]; }

Si usa esto, asegúrese de conectar la altura de vista de tabla correcta en la segunda instrucción if. Espero que esto sea útil para alguien.


En iOS9 tuve el problema de que cambiar las inserciones separadoras también afecta el posicionamiento del texto y la etiqueta de detalles.

Lo resolví con esto

override func layoutSubviews() { super.layoutSubviews() separatorInset = UIEdgeInsets(top: 0, left: layoutMargins.left, bottom: 0, right: width - layoutMargins.left) }


En su subclase UITableViewCell, anule layoutSubviews y oculte el _UITableViewCellSeparatorView. Funciona bajo iOS 10.

override func layoutSubviews() { super.layoutSubviews() subviews.forEach { (view) in if view.dynamicType.description() == "_UITableViewCellSeparatorView" { view.hidden = true } } }


Funciona para mí cuando uso la extensión y la llamada dentro de layoutSubviews () para actualizar las vistas de diseño inmediatamente.

extension UITableViewCell { func removeSeparator() { separatorInset = UIEdgeInsetsMake(0, bounds.size.width, 0, 0) } } override func layoutSubviews() { super.layoutSubviews() removeSeparator() }


La mejor manera de lograr esto es desactivar los separadores de línea predeterminados, subclase UITableViewCell y agregar un separador de línea personalizado como una subvista de la contentView . ticker y name :

import UIKit private let kSNStockCellCellHeight: CGFloat = 65.0 private let kSNStockCellCellLineSeparatorHorizontalPaddingRatio: CGFloat = 0.03 private let kSNStockCellCellLineSeparatorBackgroundColorAlpha: CGFloat = 0.3 private let kSNStockCellCellLineSeparatorHeight: CGFloat = 1 class SNStockCell: UITableViewCell { private let primaryTextColor: UIColor private let secondaryTextColor: UIColor private let customLineSeparatorView: UIView var showsCustomLineSeparator: Bool { get { return !customLineSeparatorView.hidden } set(showsCustomLineSeparator) { customLineSeparatorView.hidden = !showsCustomLineSeparator } } var customLineSeparatorColor: UIColor? { get { return customLineSeparatorView.backgroundColor } set(customLineSeparatorColor) { customLineSeparatorView.backgroundColor = customLineSeparatorColor?.colorWithAlphaComponent(kSNStockCellCellLineSeparatorBackgroundColorAlpha) } } required init(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } init(reuseIdentifier: String, primaryTextColor: UIColor, secondaryTextColor: UIColor) { self.primaryTextColor = primaryTextColor self.secondaryTextColor = secondaryTextColor self.customLineSeparatorView = UIView(frame:CGRectZero) super.init(style: UITableViewCellStyle.Subtitle, reuseIdentifier:reuseIdentifier) selectionStyle = UITableViewCellSelectionStyle.None backgroundColor = UIColor.clearColor() contentView.addSubview(customLineSeparatorView) customLineSeparatorView.hidden = true } override func prepareForReuse() { super.prepareForReuse() self.showsCustomLineSeparator = false } // MARK: Layout override func layoutSubviews() { super.layoutSubviews() layoutCustomLineSeparator() } private func layoutCustomLineSeparator() { let horizontalPadding: CGFloat = bounds.width * kSNStockCellCellLineSeparatorHorizontalPaddingRatio let lineSeparatorWidth: CGFloat = bounds.width - horizontalPadding * 2; customLineSeparatorView.frame = CGRectMake(horizontalPadding, kSNStockCellCellHeight - kSNStockCellCellLineSeparatorHeight, lineSeparatorWidth, kSNStockCellCellLineSeparatorHeight) } // MARK: Public Class API class func cellHeight() -> CGFloat { return kSNStockCellCellHeight } // MARK: Public API func configureWithStock(stock: SNStock) { textLabel!.text = stock.ticker as String textLabel!.textColor = primaryTextColor detailTextLabel!.text = stock.name as String detailTextLabel!.textColor = secondaryTextColor setNeedsLayout() } }

Para deshabilitar el uso predeterminado del separador de línea, tableView.separatorStyle = UITableViewCellSeparatorStyle.None; . El lado del consumidor es relativamente simple, vea el siguiente ejemplo:

private func stockCell(tableView: UITableView, indexPath:NSIndexPath) -> UITableViewCell { var cell : SNStockCell? = tableView.dequeueReusableCellWithIdentifier(stockCellReuseIdentifier) as? SNStockCell if (cell == nil) { cell = SNStockCell(reuseIdentifier:stockCellReuseIdentifier, primaryTextColor:primaryTextColor, secondaryTextColor:secondaryTextColor) } cell!.configureWithStock(stockAtIndexPath(indexPath)) cell!.showsCustomLineSeparator = true cell!.customLineSeparatorColor = tintColor return cell! }


Lo mucho más simple y lógico es hacer esto:

- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section { return [[UIView alloc] initWithFrame:CGRectZero]; }

En la mayoría de los casos, no desea ver solo el último separador tableCiewCell. Y este enfoque elimina solo el último separador de tableViewCell, y no necesita pensar en los problemas de reproducción automática (es decir, el dispositivo giratorio) o los valores de codificación para configurar las inserciones de los separadores.


Mejor solución para iOS 7 y 8

-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { DLog(@""); if (cell && indexPath.row == 0 && indexPath.section == 0) { DLog(@"cell.bounds.size.width %f", cell.bounds.size.width); cell.separatorInset = UIEdgeInsetsMake(0.f, cell.bounds.size.width, 0.f, 0.0f); } }

Si su aplicación es giratoria, use 3000.0f para la constante de inserción izquierda o calcúlelo sobre la marcha. Si intenta establecer el recuadro derecho, tiene una parte visible del separador en el lado izquierdo de la celda en iOS 8.


Mi requerimiento era ocultar el separador entre 4ta y 5ta celda. Lo logré por

-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { if(indexPath.row == 3) { cell.separatorInset = UIEdgeInsetsMake(0, cell.bounds.size.width, 0, 0); } }


No creo que este enfoque funcione bajo ninguna circunstancia con celdas dinámicas ...

if (indexPath.row == self.newCarArray.count-1) { cell.separatorInset = UIEdgeInsetsMake(0.f, cell.bounds.size.width, 0.f, 0.f); }

No importa en qué método de vista de tabla lo haga para las celdas dinámicas, la celda en la que cambió la propiedad de inserción siempre tendrá la propiedad de inserción establecida ahora cada vez que se elimine de la cola, causando un alboroto de separadores de líneas faltantes ... Eso es hasta que cambiarlo a ti mismo.

Algo como esto funcionó para mí:

if indexPath.row == franchises.count - 1 { cell.separatorInset = UIEdgeInsetsMake(0, cell.contentView.bounds.width, 0, 0) } else { cell.separatorInset = UIEdgeInsetsMake(0, 0, cell.contentView.bounds.width, 0) }

De esa manera usted actualiza su estado de la estructura de datos en cada carga


No pude ocultar el separador en una celda específica excepto utilizando la siguiente solución alternativa

- (void)layoutSubviews { [super layoutSubviews]; [self hideCellSeparator]; } // workaround - (void)hideCellSeparator { for (UIView *view in self.subviews) { if (![view isKindOfClass:[UIControl class]]) { [view removeFromSuperview]; } } }


Para dar seguimiento a la respuesta de Hiren .

en ViewDidLoad y la siguiente línea:

self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;

O, si está utilizando XIB o Storyboards, cambie el " separador " a " ninguno ":

Y en CellForRowAtIndexPath agrega esto:

CGFloat separatorInset; // Separator x position CGFloat separatorHeight; CGFloat separatorWidth; CGFloat separatorY; UIImageView *separator; UIColor *separatorBGColor; separatorY = cell.frame.size.height; separatorHeight = (1.0 / [UIScreen mainScreen].scale); // This assures you to have a 1px line height whatever the screen resolution separatorWidth = cell.frame.size.width; separatorInset = 15.0f; separatorBGColor = [UIColor colorWithRed: 204.0/255.0 green: 204.0/255.0 blue: 204.0/255.0 alpha:1.0]; separator = [[UIImageView alloc] initWithFrame:CGRectMake(separatorInset, separatorY, separatorWidth,separatorHeight)]; separator.backgroundColor = separatorBGColor; [cell addSubView: separator];

Aquí hay un ejemplo del resultado donde muestro una vista de tabla con celdas dinámicas (pero solo tengo una con contenido). El resultado es que solo uno tiene un separador y no todas las vistas de tabla "ficticias" se agregan automáticamente para llenar la pantalla.

Espero que esto ayude.

EDITAR: Para aquellos que no siempre leen los comentarios, en realidad hay una mejor manera de hacerlo con unas pocas líneas de código:

override func viewDidLoad() { super.viewDidLoad() tableView.tableFooterView = UIView() }


Para iOS7 y superior, la forma más limpia es usar INFINITY en lugar de un valor codificado. No tiene que preocuparse por actualizar la celda cuando la pantalla gira.

if (indexPath.row == <row number>) { cell.separatorInset = UIEdgeInsetsMake(0, INFINITY, 0, 0); }


Pruebe el siguiente código, podría ayudarlo a resolver su problema

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSString* reuseIdentifier = @"Contact Cell"; UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier]; if (nil == cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier]; if (indexPath.row != 10) {//Specify the cell number cell.backgroundView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"bgWithLine.png"]]; } else { cell.backgroundView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"bgWithOutLine.png"]]; } } return cell; }


Puede utilizar el siguiente código:

Swift:

if indexPath.row == {your row number} { cell.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: .greatestFiniteMagnitude) }

o:

cell.separatorInset = UIEdgeInsetsMake(0, 0, 0, UIScreen.main.bounds.width)

para el margen predeterminado:

cell.separatorInset = UIEdgeInsetsMake(0, tCell.layoutMargins.left, 0, 0)

para mostrar separador de extremo a extremo

cell.separatorInset = .zero

C objetivo:

if (indexPath.row == {your row number}) { cell.separatorInset = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, CGFLOAT_MAX); }


Rápido:

public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { ... // remove separator for last cell cell.separatorInset = indexPath.row < numberOfRowsInSection-1 ? tableView.separatorInset : UIEdgeInsets(top: 0, left: tableView.bounds.size.width, bottom: 0, right: 0) return cell }

C objetivo:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { ... // remove separator for last cell cell.separatorInset = (indexPath.row < numberOfRowsInSection-1) ? tableView.separatorInset : UIEdgeInsetsMake(0.f, tableView.bounds.size.width, 0.f, 0.f); return cell; }


Si la respuesta aceptada no funciona, puedes intentar esto:

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { return 0.01f; }

Es genial ;)


Si no quieres dibujar el separador, usa esto:

// Hide the cell separator by moving it to the far right cell.separatorInset = UIEdgeInsetsMake(0, 10000, 0, 0);

Sin embargo, esta API solo está disponible a partir de iOS 7.


Usando Swift 3 y adoptando el método de pirateo más rápido, puede mejorar el código usando extensiones :

extension UITableViewCell { var isSeparatorHidden: Bool { get { return self.separatorInset.right != 0 } set { if newValue { self.separatorInset = UIEdgeInsetsMake(0, self.bounds.size.width, 0, 0) } else { self.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0) } } } }

Luego, cuando configures la celda:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "identifier", for: indexPath) switch indexPath.row { case 3: cell.isSeparatorHidden = true default: cell.isSeparatorHidden = false } return cell } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let cell = tableView.cellForRow(at: indexPath) if cell.isSeparatorHidden { // do stuff } }


Use esta subclase, set separatorInset no funciona para iOS 9.2.1, el contenido se comprimiría.

@interface NSPZeroMarginCell : UITableViewCell @property (nonatomic, assign) BOOL separatorHidden; @end @implementation NSPZeroMarginCell - (void) layoutSubviews { [super layoutSubviews]; for (UIView *view in self.subviews) { if (![view isKindOfClass:[UIControl class]]) { if (CGRectGetHeight(view.frame) < 3) { view.hidden = self.separatorHidden; } } } } @end

https://gist.github.com/liruqi/9a5add4669e8d9cd3ee9


en viewDidLoad , agregue esta línea:

self.tableView.separatorColor = [UIColor clearColor];

y en cellForRowAtIndexPath :

para versiones inferiores de iOS

if(indexPath.row != self.newCarArray.count-1){ UIImageView *line = [[UIImageView alloc] initWithFrame:CGRectMake(0, 44, 320, 2)]; line.backgroundColor = [UIColor redColor]; [cell addSubview:line]; }

para las versiones superiores de iOS 7 (incluido iOS 8)

if (indexPath.row == self.newCarArray.count-1) { cell.separatorInset = UIEdgeInsetsMake(0.f, cell.bounds.size.width, 0.f, 0.f); }


mi entorno de desarrollo es

  • Xcode 7.0
  • 7A220 Swift 2.0
  • iOS 9.0

Las respuestas anteriores no funcionan completamente para mí

Después de intentarlo, mi solución que finalmente funciona es:

let indent_large_enought_to_hidden:CGFloat = 10000 cell.separatorInset = UIEdgeInsetsMake(0, indent_large_enought_to_hidden, 0, 0) // indent large engough for separator(including cell'' content) to hidden separator cell.indentationWidth = indent_large_enought_to_hidden * -1 // adjust the cell''s content to show normally cell.indentationLevel = 1 // must add this, otherwise default is 0, now actual indentation = indentationWidth * indentationLevel = 10000 * 1 = -10000

y el efecto es:


if([_data count] == 0 ){ [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];// [self tableView].=YES; } else { [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleSingleLine];//// [self tableView].hidden=NO; }


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSString *cellId = @"cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId]; NSInteger lastRowIndexInSection = [tableView numberOfRowsInSection:indexPath.section] - 1; if (row == lastRowIndexInSection) { CGFloat halfWidthOfCell = cell.frame.size.width / 2; cell.separatorInset = UIEdgeInsetsMake(0, halfWidthOfCell, 0, halfWidthOfCell); } }


cell.separatorInset = UIEdgeInsetsMake(0.0, cell.bounds.size.width, 0.0, -cell.bounds.size.width)

Funciona bien en iOS 10.2