2009-06-06 9 views
28

Por razones de rendimiento, es habitual reutilizar las celdas UITableView '. ¿Hay alguna manera de hacer lo mismo con las vistas del encabezado de TableView? Estoy hablando de los que se devuelven con el método de delegado:Vistas del encabezado de TableView reutilizables

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section 

he tratado de hacer lo siguiente, que no parece estar funcionando como se esperaba:

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section 
{ 
    static NSString *CellIdentifier = @"Header"; 

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: CellIdentifier]; 
    if (cell == nil) { 
     cell = [self getHeaderContentView: CellIdentifier]; 
    } 
    return cell; 
} 

¿Hay una manera de reutilizar las vistas del encabezado?

+1

A partir de iOS 6 ahora tiene 'UITableViewHeaderFooterView' que hace uso de la reuseIdentifier. – h4xnoodle

+0

Pero actualmente no puede usar UITableViewHeaderFooterView con UI Builder. –

Respuesta

32

La razón por la que Apple incorporó la capacidad de reutilizar celdas de tabla vista se debe a que, aunque la tabla vista puede tener muchas filas, solo se muestran unas pocas en la pantalla. En lugar de asignar memoria para cada celda, las aplicaciones pueden reutilizar las ya existentes y reconfigurarlas según sea necesario.

En primer lugar, las vistas de encabezado son solo UIViews, y aunque UITableViewCell es una subclase de UIView, no están destinadas a ser ubicadas como la vista de un encabezado de sección.

Además, dado que generalmente tendrá muchos menos encabezados de sección que filas totales, hay pocas razones para construir un mecanismo de reutilización y, de hecho, Apple no ha implementado uno para UIViews genéricos.

Tenga en cuenta que si solo está configurando una etiqueta en el encabezado, puede usar -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section en su lugar.

Para algo más personalizado, como una etiqueta con el texto en rojo (o un botón, imagen, etc.), se puede hacer algo como esto:

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { 
    UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(0,0, 320, 44)] autorelease]; 
    UILabel *label = [[[UILabel alloc] initWithFrame:headerView.frame] autorelease]; 
    label.textColor = [UIColor redColor]; 
    label.text = [NSString stringWithFormat:@"Section %i", section]; 

    [headerView addSubview:label]; 
    return headerView; 
} 
+0

Creo que la etiqueta no se debe liberar automáticamente, sino que se liberará una vez que se haya agregado a headerView. ¿Que estas pensando? – gsempe

+14

"hay pocas razones para construir un mecanismo de reutilización ..."El comentario de Martins es generalmente correcto, pero no del todo. Para cualquiera que intente alcanzar los 60 fps (como yo), viewForHeaderInSection, con una vista personalizada, es el diablo. Ingresar una nueva vista para cada encabezado, especialmente si tus grupos no son grandes , virtualmente hará que sea imposible alcanzar dicho rendimiento, ya que normalmente me costará 5 FPS. Si puede evitar los encabezados personalizados en su diseño, le dará un aumento de rendimiento. –

+2

Pero, ¿qué sucede si realmente necesita utilizar vistas de encabezado personalizado? , ¿cuál es la mejor manera de mantener el FPS en 60? –

10

Una solución sencilla y eficaz:

@interface SectionedTableViewController() 
    @property (nonatomic, strong) UINib*   sectionHeaderNib; 
    @property (nonatomic, strong) NSMutableArray* sectionHeaders; 
@end 

@implementation SectionedTableViewController 

@synthesize sectionHeaderNib = sectionHeaderNib_; 
@synthesize sectionHeaders = sectionHeaders_; 

- (void) viewDidUnload 
{ 
    self.sectionHeaders = nil; 
    [super viewDidUnload]; 
} 

- (NSMutableArray*) sectionHeaders 
{ 
    if (!sectionHeaders_) 
     self.sectionHeaders = [NSMutableArray array]; 
    return sectionHeaders_; 
} 


- (UINib*) sectionHeaderNib 
{ 
    if (!sectionHeaderNib_) 
     self.sectionHeaderNib = [UINib nibWithNibName: NSStringFromClass(YourHeaderView.class) bundle: nil]; 
    return sectionHeaderNib_; 
} 


- (YourHeaderView*) dequeueHeader 
{ 
    return [self.sectionHeaders firstObjectPassingTest: ^(id obj) { return (BOOL) ([obj superview] == nil); }]; 
} 


- (NSString*) sectionHeaderTitleForSection: (NSInteger) section 
{ 
    return nil; 
} 


- (UIView*) tableView: (UITableView*) tableView viewForHeaderInSection: (NSInteger) section 
{ 
    YourHeaderView* headerView = [self dequeueHeader]; 
    if (!headerView) 
    { 
     headerView = [YourHeaderView instanceFromNib: self.sectionHeaderNib]; 
     [self.sectionHeaders addObject: headerView]; 
    } 
    return headerView; 
} 

@end 
+0

¿Qué es esto: firstObjectPassingTest? –

7

puede implementar que mediante la creación UITableViewHeaderFooterView clase es subclase de UIView también es necesario crear un indi XIB vidual ya que no se creará automáticamente con UITableViewHeaderFooterView creación.

Registro plumilla con tableview

[self.tblCart registerNib:[UINib nibWithNibName:@"CartHeaderView" bundle:nil] forHeaderFooterViewReuseIdentifier:@"CartHeader"]; 

Ahora puede acceder a que, en viewForHeaderInSection

-(UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section 
{ 

    CartHeaderView *sectionHeader=[tableView dequeueReusableHeaderFooterViewWithIdentifier:@"CartHeader"]; 
return sectionHeader; 
} 

Nota: Para establecer el color de fondo que tendrá que crear una vista secundaria con el mismo marco que la sección encabezado y establecer color para esa vista.

puede seguir

Changing the background color on a UITableViewHeaderFooterView loaded from a xib says to use contentView.backgroundColor instead

Cuestiones relacionadas