uitableviewcontroller tutorial personalizadas example celdas uitableview ios5 uistoryboard

tutorial - uitableviewcontroller swift 4



Cómo implementar secciones y encabezados de sección de vista de tabla personalizada con Storyboard (15)

  1. Agregar celda en StoryBoard y establecer reuseidentified

  2. Código

    class TP_TaskViewTableViewSectionHeader: UITableViewCell{ }

    y

  3. Utilizar:

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let header = tableView.dequeueReusableCell(withIdentifier: "header", for: IndexPath.init(row: 0, section: section)) return header }

Sin usar un guión gráfico, simplemente podríamos arrastrar una UIView en el lienzo, colocarla y luego configurarla en los tableView:viewForHeaderInSection o tableView:viewForFooterInSection .

¿Cómo logramos esto con StoryBoard donde no podemos arrastrar una UIView en el lienzo?


¿Qué pasa con una solución donde el encabezado se basa en una matriz de vista:

class myViewController: UIViewController { var header: [UILabel] = myStringArray.map { (thisTitle: String) -> UILabel in let headerView = UILabel() headerView.text = thisTitle return(headerView) }

Siguiente en el delegado:

extension myViewController: UITableViewDelegate { func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { return(header[section]) } }


Aquí está la respuesta de @Vitaliy Gozhenko , en Swift.
Para resumir, creará una UITableViewHeaderFooterView que contiene una UITableViewCell. Esta UITableViewCell será "dequeuable" y puedes diseñarla en tu guión gráfico.

  1. Crear una clase UITableViewHeaderFooterView

    class CustomHeaderFooterView: UITableViewHeaderFooterView { var cell : UITableViewCell? { willSet { cell?.removeFromSuperview() } didSet { if let cell = cell { cell.frame = self.bounds cell.autoresizingMask = [UIViewAutoresizing.FlexibleHeight, UIViewAutoresizing.FlexibleWidth] self.contentView.backgroundColor = UIColor .clearColor() self.contentView .addSubview(cell) } } }

  2. Conecte su vista de tabla con esta clase en su función viewDidLoad:

    self.tableView.registerClass(CustomHeaderFooterView.self, forHeaderFooterViewReuseIdentifier: "SECTION_ID")

  3. Al preguntar, para un encabezado de sección, dequeue un CustomHeaderFooterView, e inserte una celda en él

    func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let view = self.tableView.dequeueReusableHeaderFooterViewWithIdentifier("SECTION_ID") as! CustomHeaderFooterView if view.cell == nil { let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell") view.cell = cell; } // Fill the cell with data here return view; }


Cuando devuelvas contentView de la celda tendrás 2 problemas:

  1. accidente relacionado con gestos
  2. no reutiliza ContentView (siempre en la llamada viewForHeaderInSection , está creando una nueva celda)

Solución:

Clase de contenedor para encabezado de tabla / pie de página. Es solo contenedor, heredado de UITableViewHeaderFooterView , que contiene la celda dentro

https://github.com/Magnat12/MGTableViewHeaderWrapperView.git

Clase de registro en su UITableView (por ejemplo, en viewDidLoad)

- (void)viewDidLoad { [super viewDidLoad]; [self.tableView registerClass:[MGTableViewHeaderWrapperView class] forHeaderFooterViewReuseIdentifier:@"ProfileEditSectionHeader"]; }

En su UITableViewDelegate:

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { MGTableViewHeaderWrapperView *view = [tableView dequeueReusableHeaderFooterViewWithIdentifier:@"ProfileEditSectionHeader"]; // init your custom cell ProfileEditSectionTitleTableCell *cell = (ProfileEditSectionTitleTableCell * ) view.cell; if (!cell) { cell = [tableView dequeueReusableCellWithIdentifier:@"ProfileEditSectionTitleTableCell"]; view.cell = cell; } // Do something with your cell return view; }


Deberías usar la solución de Tieme como base pero olvidarte de viewWithTag: y otros enfoques sospechosos, en su lugar intenta volver a cargar tu encabezado (volviendo a cargar esa sección).

Entonces, después de que haya sentado la vista de encabezado de celda personalizada con todas las cosas elegantes de AutoLayout, simplemente dequeue y devuelva contentView después de su configuración, como:

-(UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { static NSString *CellIdentifier = @"SectionHeader"; SettingsTableViewCell *sectionHeaderCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; sectionHeaderCell.myPrettyLabel.text = @"Greetings"; sectionHeaderCell.contentView.backgroundColor = [UIColor whiteColor]; // don''t leave this transparent return sectionHeaderCell.contentView; }


En iOS 6.0 y versiones superiores, las cosas han cambiado con la nueva API dequeueReusableHeaderFooterViewWithIdentifier .

He escrito una samwize.com/2015/11/06/… (probada en iOS 9), que se puede resumir como tal:

  1. Subclase UITableViewHeaderFooterView
  2. Cree Nib con la vista de subclase y agregue 1 vista de contenedor que contenga todas las demás vistas en el encabezado / pie de página
  3. Registre el Nib en viewDidLoad
  4. Implementa viewForHeaderInSection y utiliza dequeueReusableHeaderFooterViewWithIdentifier para recuperar el encabezado / pie de página

He estado en problemas en un escenario en el que Header nunca se reutilizó, incluso haciendo todos los pasos adecuados.

Así que como nota de sugerencia para todos los que quieran lograr la situación de mostrar secciones vacías (0 filas) advierta que:

dequeueReusableHeaderFooterViewWithIdentifier no reutilizará el encabezado hasta que devuelva al menos una fila

Espero eso ayude


La solución que se me ocurrió es básicamente la misma solución utilizada antes de la introducción de guiones gráficos.

Crea un nuevo archivo de clase de interfaz vacío. Arrastre un UIView al lienzo, diseño como desee.

Cargue el plumín de forma manual, asígnelo a la sección de encabezado / pie de página correspondiente en los métodos de delegado viewForHeaderInSection o viewForFooterInSection.

Tenía la esperanza de que Apple simplificara este escenario con guiones gráficos y siguiera buscando una solución mejor o más simple. Por ejemplo, los encabezados y pies de tabla personalizados son sencillos de agregar.


Lo tengo trabajando en iOS7 usando una celda prototipo en el guión gráfico. Tengo un botón en la vista del encabezado de la sección personalizada que activa un segue que está configurado en el guión gráfico.

Comience con la solución de Tieme

Como señala pedro.m, el problema es que al tocar el encabezado de sección se selecciona la primera celda de la sección.

Como señala Paul Von, esto se soluciona devolviendo el contentView de la celda en lugar de la celda completa.

Sin embargo, como señala Hons, una pulsación larga en dicho encabezado de sección bloqueará la aplicación.

La solución es eliminar cualquier gestureRecognizers de contentView.

-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { static NSString *CellIdentifier = @"SectionHeader"; UITableViewCell *sectionHeaderView = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; while (sectionHeaderView.contentView.gestureRecognizers.count) { [sectionHeaderView.contentView removeGestureRecognizer:[sectionHeaderView.contentView.gestureRecognizers objectAtIndex:0]]; } return sectionHeaderView.contentView; }

Si no está usando gestos en las vistas de encabezado de su sección, parece que este pequeño truco lo hace.


Para dar seguimiento a la sugerencia de Damon , aquí es cómo hice que el encabezado se seleccionara como una fila normal con un indicador de divulgación.

Agregué un botón subclasificado desde UIButton (nombre de la subclase "ButtonWithArgument") a la celda del prototipo del encabezado y borré el texto del título (el texto en negrita "Title" es otro UILabel en la celda del prototipo)

luego, configure el Botón en la vista del encabezado completo y agregue un indicador de divulgación con el truco de Avario

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { static NSString *CellIdentifier = @"PersonGroupHeader"; UITableViewCell *headerView = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if(headerView == nil) { [NSException raise:@"headerView == nil, PersonGroupTableViewController" format:[NSString stringWithFormat:@"Storyboard does not have prototype cell with identifier %@",CellIdentifier]]; } // https://.com/a/24044628/3075839 while(headerView.contentView.gestureRecognizers.count) { [headerView.contentView removeGestureRecognizer:[headerView.contentView.gestureRecognizers objectAtIndex:0]]; } ButtonWithArgument *button = (ButtonWithArgument *)[headerView viewWithTag:4]; button.frame = headerView.bounds; // set tap area to entire header view button.argument = [[NSNumber alloc] initWithInteger:section]; // from ButtonWithArguments subclass [button addTarget:self action:@selector(headerViewTap:) forControlEvents:UIControlEventTouchUpInside]; // https://.com/a/20821178/3075839 UITableViewCell *disclosure = [[UITableViewCell alloc] init]; disclosure.accessoryType = UITableViewCellAccessoryDisclosureIndicator; disclosure.userInteractionEnabled = NO; disclosure.frame = CGRectMake(button.bounds.origin.x + button.bounds.size.width - 20 - 5, // disclosure 20 px wide, right margin 5 px (button.bounds.size.height - 20) / 2, 20, 20); [button addSubview:disclosure]; // configure header title text return headerView.contentView; } - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { return 35.0f; } -(void) headerViewTap:(UIGestureRecognizer *)gestureRecognizer; { NSLog(@"header tap"); NSInteger section = ((NSNumber *)sender.argument).integerValue; // do something here }

ButtonWithArgument.h

#import <UIKit/UIKit.h> @interface ButtonWithArgument : UIButton @property (nonatomic, strong) NSObject *argument; @end

ButtonWithArgument.m

#import "ButtonWithArgument.h" @implementation ButtonWithArgument @end


Sé que esta pregunta fue para iOS 5, pero para el beneficio de los futuros lectores, tenga en cuenta que con iOS 6 eficaz ahora podemos usar dequeueReusableHeaderFooterViewWithIdentifier lugar de dequeueReusableCellWithIdentifier .

Entonces, en viewDidLoad , llame a registerNib:forHeaderFooterViewReuseIdentifier: o registerClass:forHeaderFooterViewReuseIdentifier: Luego, en viewForHeaderInSection , llame a tableView:dequeueReusableHeaderFooterViewWithIdentifier: No utiliza un prototipo de celda con esta API (es una vista basada en NIB o una vista creada mediante programación), pero esta es la nueva API para encabezados y pies de página descatalogados.


Si necesita una implementación Swift de esto, siga las instrucciones en la respuesta aceptada y luego en usted UITableViewController implemente los siguientes métodos:

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let cell = self.tableView.dequeueReusableCell(withIdentifier: "CustomHeader") as! CustomHeaderUITableViewCell return cell } override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return 75 }


Si usa storyboards, puede usar una celda prototipo en la vista de tabla para diseñar su vista de encabezado. Establezca un ID único y viewForHeaderInSection, puede quitar la cola de la celda con esa ID y convertirla en una UIView.


Solía ​​hacer lo siguiente para crear vistas de cabecera / pie de página de forma perezosa:

  • Agregue un controlador de vista de forma libre para el encabezado / pie de página de la sección al guión gráfico
  • Manejar todas las cosas para el encabezado en el controlador de vista
  • En el controlador de vista de tabla, proporcione una matriz mutable de controladores de vista para los encabezados / pies de página de sección repoblados con [NSNull null]
  • En viewForHeaderInSection / viewForFooterInSection si el controlador de vista aún no existe, créelo con storyboards instanciando ViewControllerWithIdentifier, recuérdelo en la matriz y devuelva la vista de controladores de vista

Solo use un prototipo de celda como encabezado de sección y / o pie de página.

  • agregue una celda extra y coloque sus elementos deseados en ella.
  • establecer el identificador a algo específico (en mi caso SectionHeader)
  • implementar el tableView:viewForHeaderInSection: o el método tableView:viewForFooterInSection:
  • utiliza [tableView dequeueReusableCellWithIdentifier:] para obtener el encabezado
  • implementar el tableView:heightForHeaderInSection:

-(UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { static NSString *CellIdentifier = @"SectionHeader"; UITableViewCell *headerView = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (headerView == nil){ [NSException raise:@"headerView == nil.." format:@"No cells with matching CellIdentifier loaded from your storyboard"]; } return headerView; }

Editar: Cómo cambiar el título del encabezado (pregunta comentada):

  1. Agregue una etiqueta a la celda del encabezado
  2. establecer la etiqueta de la etiqueta a un número específico (por ejemplo, 123)
  3. En su tableView:viewForHeaderInSection: method obtenga la etiqueta llamando:

UILabel *label = (UILabel *)[headerView viewWithTag:123];

  1. Ahora puede usar la etiqueta para establecer un nuevo título:

[label setText:@"New Title"];