Pregunta iOS8 UITableView separator inset 0 no funciona


Tengo una aplicación donde el UITableViewLa inserción del separador está configurada en valores personalizados - Derecha 0, Izquierda 0. Esto funciona perfectamente en iOS 7.xSin embargo, en iOS 8.0 Veo que la inserción del separador está configurada en el valor predeterminado de 15 a la derecha. Aunque en los archivos xib se configuró para 0, todavía aparece incorrectamente.

¿Cómo elimino el UITableViewCell márgenes de separador?


630
2017-09-10 16:05


origen


Respuestas:


iOS 8.0 presenta la propiedad layoutMargins en celdas Y vistas de tabla.

Esta propiedad no está disponible en iOS 7.0, por lo que debe asegurarse de verificar antes de asignarla.

Además, Apple ha agregado un propiedad a su celular que evitará que herede la configuración de margen de su Vista de tabla. Cuando se establece esta propiedad, sus celdas pueden configurar sus propios márgenes independientemente de la vista de tabla. Piense en ello como una anulación.

Esta propiedad se llama preservesSuperviewLayoutMarginsy configurándolo NO permitirá que la célula layoutMargin configuración para anular cualquier cosa layoutMargin está configurado en su TableView. Ambos ahorran tiempo (no tiene que modificar la configuración de la vista de tabla), y es más conciso. Consulte la respuesta de Mike Abdullah para obtener una explicación detallada.

NOTA: lo que sigue es una implementación limpia para un ajuste de margen de nivel de celda, como se expresa en la respuesta de Mike Abdullah. Configurar las reservas de su celdaSuperviewLayoutMargins = NO garantizará que su vista de tabla no anule la configuración de la celda. Si realmente desea que su vista de tabla completa tenga márgenes consistentes, ajuste su código en consecuencia.

Configure los márgenes de su celda:

-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Remove seperator inset
    if ([cell respondsToSelector:@selector(setSeparatorInset:)]) {
           [cell setSeparatorInset:UIEdgeInsetsZero];
    }

    // Prevent the cell from inheriting the Table View's margin settings
    if ([cell respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)]) {
        [cell setPreservesSuperviewLayoutMargins:NO];
    }

    // Explictly set your cell's layout margins
    if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
        [cell setLayoutMargins:UIEdgeInsetsZero];
    }
}

Establecer la propiedad preserveSuperviewLayoutMargins en su celda a NO debería evitar que su vista de tabla anule los márgenes de su celda. En algunos casos, parece no funcionar correctamente.

Si todo falla, puede aplicar fuerza bruta a los márgenes de su Vista de tabla:

-(void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];

    // Force your tableview margins (this may be a bad idea)
    if ([self.tableView respondsToSelector:@selector(setSeparatorInset:)]) {
        [self.tableView setSeparatorInset:UIEdgeInsetsZero];
    }

    if ([self.tableView respondsToSelector:@selector(setLayoutMargins:)]) {
        [self.tableView setLayoutMargins:UIEdgeInsetsZero];
    }
} 

... y ahí tienes! Esto debería funcionar en iOS 7 y 8.

EDITAR:  Mohamed Saleh me llamó la atención sobre un posible cambio en iOS 9. Es posible que deba configurar la Vista de tabla cellLayoutMarginsFollowReadableWidth a NO si quieres personalizar las inserciones o los márgenes. Su millaje puede variar, esto no está documentado muy bien.

Esta propiedad solo existe en iOS 9, así que asegúrese de verificarla antes de configurarla.

if([myTableView respondsToSelector:@selector(setCellLayoutMarginsFollowReadableWidth:)])
{
    myTableView.cellLayoutMarginsFollowReadableWidth = NO;
} 

(arriba código de iOS8 UITableView separator inset 0 no funciona)

EDITAR: Aquí hay un enfoque puro de Interface Builder:

TableViewAttributesInspector TableViewCellSizeInspector

NOTA: iOS 11 cambia y simplifica gran parte de este comportamiento, se actualizará próximamente ...


1048
2017-09-16 20:19



Arg !!! Después de jugar, ya sea haciendo esto en tu Cell subclase:

- (UIEdgeInsets)layoutMargins
{
    return UIEdgeInsetsZero;
}

o establecer el cell.layoutMargins = UIEdgeInsetsZero; me lo arregló


251
2017-09-10 18:02



Tomemos un momento para comprender el problema antes de cargar a ciegas para tratar de arreglarlo.

Un rápido vistazo en el depurador le dirá que las líneas separadoras son subvistas de UITableViewCell. Parece que la célula misma asume una gran cantidad de responsabilidad por el diseño de estas líneas.

iOS 8 presenta el concepto de márgenes de diseño. Por defecto, los márgenes de diseño de una vista son 8pt por todos lados, y están heredado desde las vistas de los antepasados.

Lo mejor que podemos decir, al diseñar su línea de separación, UITableViewCell elige respetar el margen de diseño de la izquierda, usándolo para restringir el recuadro de la izquierda.

Poniendo todo eso junto, para lograr el recuadro deseado de verdaderamente cero, tenemos que:

  • Establezca el margen de diseño izquierdo en 0
  • Detenga cualquier margen heredado anulando ese

Puesto así, es una tarea bastante simple de lograr:

cell.layoutMargins = UIEdgeInsetsZero;
cell.preservesSuperviewLayoutMargins = NO;

Cosas a tener en cuenta:

  • Este código solo necesariamente para que se ejecute una vez por celda (después de todo, solo está configurando las propiedades de la celda), y no hay nada especial cuando elige ejecutarlo. Haz lo que te parezca más limpio.
  • Lamentablemente, no hay ninguna propiedad disponible para configurar en Interface Builder, pero puede especificar un atributo de tiempo de ejecución definido por el usuario para preservesSuperviewLayoutMargins Si es deseado.
  • Claramente, si su aplicación también se dirige a versiones anteriores del sistema operativo, deberá evitar ejecutar el código anterior hasta que se ejecute en iOS 8 o superior.
  • En lugar de establecer preservesSuperviewLayoutMargins, tú poder configurar vistas ancestrales (como la tabla) para tener 0 margen izquierdo también, pero esto parece intrínsecamente más propenso a errores ya que no controla toda la jerarquía.
  • Probablemente sería un poco más limpio establecer solo el margen izquierdo para 0 y deja los otros ser.
  • Si desea tener un recuadro 0 en los separadores "adicionales" que UITableView dibuja en la parte inferior de las tablas de estilo simple, supongo que requerirá especificar la misma configuración en el nivel de la mesa también (¡no he probado este!)

174
2017-11-09 10:49



Creo que esta es la misma pregunta que hice aquí: Eliminar SeparatorInset en iOS 8 UITableView para XCode 6 iPhone Simulator

En iOS 8, hay una propiedad nueva para todos los objetos que heredan UIView. Entonces, la solución para configurar el SeparatorInset en iOS 7.x no podrá eliminar el espacio en blanco que ve en UITableView en iOS 8.

La nueva propiedad se llama "layoutMargins".

@property(nonatomic) UIEdgeInsets layoutMargins
Description   The default spacing to use when laying out content in the view.
Availability  iOS (8.0 and later)
Declared In   UIView.h
Reference UIView Class Reference

iOS 8 UITableView setSeparatorInset:UIEdgeInsetsZero setLayoutMargins:UIEdgeInsetsZero

La solución:-

-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{

    if ([tableView respondsToSelector:@selector(setSeparatorInset:)]) {
        [tableView setSeparatorInset:UIEdgeInsetsZero];
    }

    if ([tableView respondsToSelector:@selector(setLayoutMargins:)]) {
        [tableView setLayoutMargins:UIEdgeInsetsZero];
    }

   if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
        [cell setLayoutMargins:UIEdgeInsetsZero];
   }
}

Si configura cell.layoutMargins = UIEdgeInsetsZero; sin verificar si el layoutMargins existe, la aplicación se bloqueará en iOS 7.x. Entonces, la mejor manera sería verificar si el layoutMargins existe primero antes setLayoutMargins:UIEdgeInsetsZero.


55
2017-09-11 12:54



Puede usar UIAppearance una vez, al inicio de la aplicación (antes de que se cargue la IU), para establecerlo como configuración global predeterminada:

// iOS 7:
[[UITableView appearance] setSeparatorStyle:UITableViewCellSeparatorStyleSingleLine];
[[UITableView appearance] setSeparatorInset:UIEdgeInsetsZero];

[[UITableViewCell appearance] setSeparatorInset:UIEdgeInsetsZero];

// iOS 8:
if ([UITableView instancesRespondToSelector:@selector(setLayoutMargins:)]) {

    [[UITableView appearance] setLayoutMargins:UIEdgeInsetsZero];
    [[UITableViewCell appearance] setLayoutMargins:UIEdgeInsetsZero];
    [[UITableViewCell appearance] setPreservesSuperviewLayoutMargins:NO];

}

De esta forma, mantendrá limpio el código de UIViewController y siempre podrá anularlo si lo desea.


44
2018-02-03 10:09



Versión Swift

iOS presenta la propiedad layoutMargins en celdas Y vistas de tabla.

Esta propiedad no está disponible en iOS 7.0, por lo que debe asegurarse de verificar antes de asignarla.

Sin embargo, Apple ha agregado un propiedad llamado preservaSuperviewLayoutMargins a su celular que evitará que herede la configuración de margen de su Vista de tabla. De esta manera, sus celdas pueden configurar sus propios márgenes independientemente de la vista de tabla. Piense en ello como una anulación.

Esta propiedad se llama preservaSuperviewLayoutMargins, y establecerlo en NO puede permitirle anular la configuración de layoutMargin de su vista de tabla con la configuración de layoutMargin de su propia celda. Ambos ahorran tiempo (no tiene que modificar la configuración de la vista de tabla), y es más conciso. Consulte la respuesta de Mike Abdullah para obtener una explicación detallada.

NOTA: esta es la implementación correcta y menos desordenada, como se expresa en la respuesta de Mike Abdullah; configurar las reservas de su celdaSuperviewLayoutMargins = NO asegurará que su vista de tabla no anule la configuración de la celda.

Primer paso: configure los márgenes de su celda:

/*
    Tells the delegate that the table view is about to draw a cell for a particular row.
*/
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell,
    forRowAtIndexPath indexPath: NSIndexPath)
{
    // Remove separator inset
    if cell.respondsToSelector("setSeparatorInset:") {
        cell.separatorInset = UIEdgeInsetsZero
    }

    // Prevent the cell from inheriting the Table View's margin settings
    if cell.respondsToSelector("setPreservesSuperviewLayoutMargins:") {
        cell.preservesSuperviewLayoutMargins = false
    }

    // Explictly set your cell's layout margins
    if cell.respondsToSelector("setLayoutMargins:") {
        cell.layoutMargins = UIEdgeInsetsZero
    }
}

Establecer la propiedad preserveSuperviewLayoutMargins en su celda a NO debería evitar que su vista de tabla anule los márgenes de su celda. En algunos casos, parece que no funciona correctamente.

Segundo paso: solo si todo falla, puede aplicar fuerza bruta a los márgenes de la Vista de tabla:

/*
    Called to notify the view controller that its view has just laid out its subviews.
*/
override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    // Force your tableview margins (this may be a bad idea)
    if self.tableView.respondsToSelector("setSeparatorInset:") {
        self.tableView.separatorInset = UIEdgeInsetsZero
    }

    if self.tableView.respondsToSelector("setLayoutMargins:") {
        self.tableView.layoutMargins = UIEdgeInsetsZero
    }
}

... y ahí tienes! Esto debería funcionar en iOS 8 y iOS 7.

Nota: probado con iOS 8.1 y 7.1, en mi caso solo necesitaba usar el primer paso de esta explicación.

El segundo paso solo es necesario si tiene celdas despobladas debajo de las celdas representadas, es decir. si la tabla es más grande que el número de filas en el modelo de tabla. No hacer el segundo paso daría lugar a diferentes desplazamientos de separador.


39
2017-12-23 18:34



En Swift es un poco más molesto porque layoutMargins es una propiedad, por lo que debe anular el getter y setter.

override var layoutMargins: UIEdgeInsets {
  get { return UIEdgeInsetsZero }
  set(newVal) {}
}

Esto efectivamente hará layoutMargins Readonly, que en mi caso está bien.


35
2017-09-10 21:35