Personalizar la sección de encabezado UITableView

141

Quiero personalizar el UITableViewencabezado para cada sección. Hasta ahora, he implementado

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

Este UITabelViewDelegatemétodo Lo que quiero hacer es obtener el encabezado actual para cada sección y simplemente agregarlo UILabelcomo una subvista.

Hasta ahora, no puedo lograr eso. Porque no pude encontrar nada para obtener el encabezado de sección predeterminado. Primera pregunta, ¿hay alguna forma de obtener el encabezado de sección predeterminado ?

Si no es posible, necesito crear una vista de contenedor que es un UIViewpero, esta vez necesito establecer el color de fondo predeterminado, el color de sombra, etc. Porque, si miras detenidamente el encabezado de la sección, ya está personalizado.

¿Cómo puedo obtener estos valores predeterminados para cada encabezado de sección?

Gracias a todos.

limon
fuente
1
¿Qué hay de malo en usar tableView:titleForHeaderInSection:?
Borrrden
Devuelve un NSString, necesito configurar una fuente personalizada, así que no puedo si usotableView:titleForHeaderInSection:
limon
O puede usar imágenes para imitar los encabezados de sección predeterminados. teehanlax.com/blog/ios-6-gui-psd-iphone-5
Desdenova
@limon: Cómo implementar el encabezado de sección: stackoverflow.com/a/32261262/1457385
shallowThought

Respuestas:

288

Puedes probar esto:

 -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 18)];
    /* Create custom view to display section header... */
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 5, tableView.frame.size.width, 18)];
    [label setFont:[UIFont boldSystemFontOfSize:12]];
     NSString *string =[list objectAtIndex:section];
    /* Section header is in 0th index... */
    [label setText:string];
    [view addSubview:label];
    [view setBackgroundColor:[UIColor colorWithRed:166/255.0 green:177/255.0 blue:186/255.0 alpha:1.0]]; //your background color...
    return view;
}
Ragupatía Lochana
fuente
ese es tu color bg, sea cual sea el color que quieras configurar, puedes
Lochana Ragupathy
Ese es el problema, ya hice lo que escribiste. Pero no sé el color de fondo predeterminado del encabezado de sección, que es un poco gris. Pero, necesito que sea exactamente el encabezado de sección predeterminado.
limon
15
hola vamos a usar el medidor digital de color
Lochana Ragupathy
asegúrese de establecer también el color de fondo de UILabel. Sé que estaba un poco confundido cuando mi fondo no se estaba volviendo claro para mí.
shulmey
3
¿Qué es list in line NSString * string = [list objectAtIndex: section]; Alguien me puede decir
Nisha Gupta
45

La respuesta seleccionada usando tableView :viewForHeaderInSection:es correcta.

Solo para compartir un consejo aquí.

Si está usando storyboard / xib, entonces podría crear otra celda prototipo y usarla para su "celda de sección". El código para configurar el encabezado es similar a cómo se configura para las celdas de fila.

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

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:HeaderCellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:HeaderCellIdentifier];
    }

    // Configure the cell title etc
    [self configureHeaderCell:cell inSection:section];

    return cell;
}
samwize
fuente
14
Hay varias cosas mal con esta solución. En primer lugar, el hecho de que si implementa "tableView (tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool", notará que el encabezado de la sección se moverá junto con la fila cuando se deslice. Para evitar esto, debe devolver cell.contentView en su lugar. El problema más grande es el hecho de que con esta solución, la aplicación se bloqueará cuando mantenga presionada la cabecera de la sección. La forma correcta es crear una punta que extienda UITableViewHeaderFooterView, registrarlo con la vista de tabla y devolverlo en este método. Probado en iOS8
Kachi
@Kachi La solución está usando viewForHeaderInSectionno canEditRowAtIndexPathcomo usted mencionó. Nunca verifico el bloqueo que dijiste, pero ¿podrías aclarar cómo una presión prolongada puede causar un bloqueo?
samwize
1
lo que quise decir es que si implementa esta solución e implementa canEditRowAtIndexPath, verá que el encabezado también se deslizará con la fila superior que está eliminando si no devuelve cell.contentView. Vea esta publicación SO: stackoverflow.com/questions/26009722/… La presión prolongada provoca un bloqueo porque un mensaje intenta enviarse a un objeto desasignado. Vea esta publicación SO: stackoverflow.com/questions/27622290/…
Kachi
1
No lo use nunca UITableViewCellcomo una vista de encabezado. Te resultará muy difícil depurar fallas visuales: el encabezado a veces desaparecerá debido a la deducción de las celdas y estarás buscando durante horas por qué es así hasta que te des cuenta de UITableViewCellque no pertenece al UITableViewencabezado.
raven_raven
Usar a UITableViewCellcomo encabezado es simplemente incorrecto.
Alex Zavatone
31

La versión rápida de Lochana Tejas responde:

override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let view = UIView(frame: CGRectMake(0, 0, tableView.frame.size.width, 18))
    let label = UILabel(frame: CGRectMake(10, 5, tableView.frame.size.width, 18))
    label.font = UIFont.systemFontOfSize(14)
    label.text = list.objectAtIndex(indexPath.row) as! String
    view.addSubview(label)
    view.backgroundColor = UIColor.grayColor() // Set your background color

    return view
}
estemendoza
fuente
1
¿Cómo hacer que la altura de la etiqueta sea dinámica según el texto que está dentro de la vista?
Pratik Shah
La overridepalabra clave es redundante. Además, considere reutilizar las vistas de encabezado en lugar de volver a crearlas.
Vadim Bulavin
17

Si usa la vista de encabezado predeterminada, solo puede cambiar el texto con

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section

Para Swift:

override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {

Si desea personalizar la vista, debe crear una nueva usted mismo.

Mert
fuente
10

¿Por qué no usar UITableViewHeaderFooterView ?

user836773
fuente
Solo puede usar esto si no usa también - (UIView *) tableView: (UITableView *) tableView viewForHeaderInSection: sección (NSInteger).
SAHM
1
Respuesta perfectamente válida. Además, usar UITableViewHeaderFooterView se beneficia del reciclaje de vistas al igual que las celdas.
Gregzo
66
@dmarsi No he encontrado evidencia de que estén en desuso.
Fawkes
8

Si headerInSection no se muestra, puede probar esto.

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return 45;
}

Esto devuelve una altura para el encabezado de una sección determinada.

Kathen
fuente
1
¿Te importaría elaborar tu respuesta?
CinCout
La sección del encabezado no se mostrará a menos que especifique con un método que enganche la 'altura' del encabezado de la sección. UITableView por defecto no muestra encabezados si no se especifica altura. @CinCout
theprojectabot
6

La versión Swift 3 de lochana y estemendoza responde:

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

    let view = UIView(frame: CGRect(x:0, y:0, width:tableView.frame.size.width, height:18))
    let label = UILabel(frame: CGRect(x:10, y:5, width:tableView.frame.size.width, height:18))
    label.font = UIFont.systemFont(ofSize: 14)
    label.text = "This is a test";
    view.addSubview(label);
    view.backgroundColor = UIColor.gray;
    return view

}

Además, tenga en cuenta que TAMBIÉN debe implementar:

override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return 100;
}
Adán
fuente
5

Prueba esto......

override func tableView(tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) 
{
    // Background view is at index 0, content view at index 1
    if let bgView = view.subviews[0] as? UIView
    {
        // do your stuff
    }

    view.layer.borderColor = UIColor.magentaColor().CGColor
    view.layer.borderWidth = 1
}
Gigi
fuente
5

Las otras respuestas hacen un buen trabajo al recrear la vista de encabezado predeterminada, pero en realidad no responden su pregunta principal:

¿Hay alguna forma de obtener el encabezado de sección predeterminado?

Hay una manera: simplemente implemente tableView:willDisplayHeaderView:forSection:en su delegado. La vista de encabezado predeterminada se pasará al segundo parámetro, y desde allí puede convertirla en UITableViewHeaderFooterVieway luego agregar / cambiar subvistas como desee.

Obj-C

- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
{
    UITableViewHeaderFooterView *headerView = (UITableViewHeaderFooterView *)view;

    // Do whatever with the header view... e.g.
    // headerView.textLabel.textColor = [UIColor whiteColor]
}

Rápido

override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int)
{
    let headerView = view as! UITableViewHeaderFooterView

    // Do whatever with the header view... e.g.
    // headerView.textLabel?.textColor = UIColor.white
}
Craig Brown
fuente
No necesitas lanzarlo. Simplemente puede agregar lo que desea a la vista. De hecho, crear un nuevo objeto no hará nada a menos que se lo asigne view.
Alex Zavatone
@AlexZavatone Así es, no necesita emitirlo si solo está agregando vistas. Es útil si desea personalizar algunas de las vistas predeterminadas, como la etiqueta de texto.
Craig Brown el
4
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    //put your values, this is part of my code
    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 30.0f)];
    [view setBackgroundColor:[UIColor redColor]];
    UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(20, 5, 150, 20)];
    [lbl setFont:[UIFont systemFontOfSize:18]];
    [lbl setTextColor:[UIColor blueColor]];
    [view addSubview:lbl];

    [lbl setText:[NSString stringWithFormat:@"Section: %ld",(long)section]];

    return view;
}
Boris Nikolic
fuente
4

Esta es la solución más fácil posible. El siguiente código se puede usar directamente para crear un encabezado de sección personalizado.

 -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    SectionHeaderTableViewCell *headerView = [tableView dequeueReusableCellWithIdentifier:@"sectionHeader"];

    //For creating a drop menu of rows from the section
    //==THIS IS JUST AN EXAMPLE. YOU CAN REMOVE THIS IF-ELSE.==
    if (![self.sectionCollapsedArray[section] boolValue])
    {
        headerView.imageView.image = [UIImage imageNamed:@"up_icon"];
    }
    else
    {
        headerView.imageView.image = [UIImage imageNamed:@"drop_icon"];
    }

    //For button action inside the custom cell
    headerView.dropButton.tag = section;
    [headerView.dropButton addTarget:self action:@selector(sectionTapped:) forControlEvents:UIControlEventTouchUpInside];

    //For removing long touch gestures.
    for (UIGestureRecognizer *recognizer in headerView.contentView.gestureRecognizers)
    {
        [headerView.contentView removeGestureRecognizer:recognizer];
        [headerView removeGestureRecognizer:recognizer];
    }

    return headerView.contentView;
}

NOTA: SectionHeaderTableViewCell es un UITableViewCell personalizado creado en Storyboard.

Anish Kumar
fuente
SectionHeaderTableViewCell - uso de identificador no declarado
Boris Gafurov
@BorisGafurov SectionHeaderTableViewCell es solo un nombre de ejemplo que le di a mi UITableViewCell, que creé en el guión gráfico.
Anish Kumar
2

Si yo fuera usted, haría un método que devuelva una UIView dada una NSString para contener. Por ejemplo

+ (UIView *) sectionViewWithTitle:(NSString *)title;

En la implementación de este método, cree un UIView, agregue un UILabel con las propiedades que desea establecer y, por supuesto, establezca su título en el dado.

cpprulez
fuente
Sí, puedo hacer eso, pero mi pregunta es cómo puedo obtener el fondo del encabezado de sección predeterminado, el valor de sombra, el resto es fácil de implementar.
limon
a qué te refieres con el fondo del encabezado de sección predeterminado
Lochana Ragupathy
1
Bueno, lo más fácil sería usar la aplicación Digital Color Meter para obtener los colores que desea. Tomarlos por código sería difícil, por lo que puedo decir ...
cpprulez
2

La solución de @ samwize en Swift (¡así que vota!). Brillante usando el mismo mecanismo de reciclaje también para secciones de encabezado / pie de página:

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let settingsHeaderSectionCell:SettingsHeaderSectionCell = self.dequeueReusableCell(withIdentifier: "SettingsHeaderSectionCell") as! SettingsHeaderSectionCell

    return settingsHeaderSectionCell
}
Javier Calatrava Llavería
fuente
2
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
{
    if([view isKindOfClass:[UITableViewHeaderFooterView class]]){

        UITableViewHeaderFooterView *headerView = view;

        [[headerView textLabel] setTextColor:[UIColor colorWithHexString:@"666666"]];
        [[headerView textLabel] setFont:[UIFont fontWithName:@"fontname" size:10]];
    }
}

Si desea cambiar la fuente de textLabel en el encabezado de su sección, desea hacerlo en willDisplayHeaderView. Para configurar el texto, puede hacerlo en viewForHeaderInSection o titleForHeaderInSection. ¡Buena suerte!

John Ottenlips
fuente
2

Ejemplo completo de 2019 para copiar y pegar

Primero configure "Agrupado" en el guión gráfico: tiene que suceder en el momento inicial, realmente no puede configurarlo más tarde, por lo que es más fácil recordar hacerlo en el guión gráfico:

ingrese la descripción de la imagen aquí

Próximo,

Debe implementar heightForHeaderInSection debido a un error de Apple.

func tableView(_ tableView: UITableView,
                   heightForHeaderInSection section: Int) -> CGFloat {
    return CGFloat(70.0)
}

Todavía hay un error de Apple, durante diez años, donde simplemente no mostrará el primer encabezado (es decir, el índice 0) si no tiene heightForHeaderInSection llamada.

Entonces, tableView.sectionHeaderHeight = 70simplemente no funciona, está roto .

Establecer un marco no logra nada:

En viewForHeaderInSection simplemente crear un UIView ().

No tiene sentido / no logra nada si UIView (marco ...) ya que iOS simplemente establece el tamaño de la vista según lo determinado por la tabla.

Entonces, la primera línea de viewForHeaderInSectionserá simple let view = UIView()y esa es la vista que devuelve.

func tableView(_ tableView: UITableView,
                       viewForHeaderInSection section: Int) -> UIView? {
    let view = UIView()
    
    let l = UILabel()
    view.addSubview(l)
    l.bindEdgesToSuperview()
    l.backgroundColor = .systemOrange
    l.font = UIFont.systemFont(ofSize: 15)
    l.textColor = .yourClientsFavoriteColor
    
    switch section {
    case 0:
        l.text =  "First section on screen"
    case 1:
        l.text =  "Here's the second section"
    default:
        l.text =  ""
    }
    
    return view
}

Eso es todo, cualquier otra cosa es una pérdida de tiempo.

Otro problema de Apple "quisquilloso".


La extensión de conveniencia utilizada anteriormente es:

extension UIView {
    
    // incredibly useful:
    
    func bindEdgesToSuperview() {
        
        guard let s = superview else {
            preconditionFailure("`superview` nil in bindEdgesToSuperview")
        }
        
        translatesAutoresizingMaskIntoConstraints = false
        leadingAnchor.constraint(equalTo: s.leadingAnchor).isActive = true
        trailingAnchor.constraint(equalTo: s.trailingAnchor).isActive = true
        topAnchor.constraint(equalTo: s.topAnchor).isActive = true
        bottomAnchor.constraint(equalTo: s.bottomAnchor).isActive = true
    }
}
Fattie
fuente
1

Agregue mágicamente el encabezado de vista de tabla rápidamente

Recientemente probé esto.

Necesitaba uno y solo un encabezado en todo UITableView.

Como si quisiera un UIImageView en la parte superior de TableView. Así que agregué un UIImageView encima de UITableViewCell y automáticamente se agregó como tableViewHeader. Ahora conecto el ImageView al ViewController y agrego la imagen.

Estaba confundido porque hice algo así por primera vez. Entonces, para aclarar mi confusión, abra el formato xml de MainStoryBoard y descubrí que la Vista de imagen se agregó como encabezado.

Funcionó para mi. Gracias xCode y swift.

Somir Saikia
fuente
1

llamar a este método delegado

-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{

return @"Some Title";
}

esto le dará la oportunidad de agregar automáticamente un encabezado predeterminado con título dinámico.

Puede usar encabezado / pie de página reutilizable y personalizable.

https://github.com/sourov2008/UITableViewCustomHeaderFooterSection

Shourob Datta
fuente
1

swif 4.2

override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
    guard let header = view as? UITableViewHeaderFooterView else { return }

    header.textLabel?.textAlignment = .center // for all sections

    switch section {
    case 1:  //only section No.1
        header.textLabel?.textColor = .black
    case 3:  //only section No.3
        header.textLabel?.textColor = .red
    default: //
        header.textLabel?.textColor = .yellow
    }
}
flowGlen
fuente
0

Si solo desea agregar un título al encabezado tableView, no agregue una vista. En swift 3.x el código es así:

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    var lblStr = ""
    if section == 0 {
        lblStr = "Some String 1"
    }
    else if section == 1{
        lblStr = "Some String 2"
    }
    else{
        lblStr = "Some String 3"
    }
    return lblStr
}

Puede implementar una matriz para obtener el título de los encabezados.

abhishek chakrabartti
fuente
0

Volviendo a la pregunta original (4 años después), en lugar de reconstruir su propio encabezado de sección, iOS simplemente puede llamarlo (con willDisplayHeaderView: forSection :) justo después de haber creado el predeterminado. Por ejemplo, quería agregar un botón de gráfico en el borde derecho del encabezado de sección:

- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section {
    UITableViewHeaderFooterView * header = (UITableViewHeaderFooterView *) view;
    if (header.contentView.subviews.count >  0) return; //in case of reuse
    CGFloat rightEdge = CGRectGetMaxX(header.contentView.bounds);
    UIButton * button = [[UIButton alloc] initWithFrame:CGRectMake(rightEdge - 44, 0, 44, CGRectGetMaxY(header.contentView.bounds))];
    [button setBackgroundImage:[UIImage imageNamed:@"graphIcon"] forState:UIControlStateNormal];
    [button addTarget:self action:@selector(graphButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
    [view addSubview:button];
}
Mackworth
fuente
0

Utilizar tableView: willDisplayHeaderView: para personalizar la vista cuando esté a punto de mostrarse.

Esto le brinda la ventaja de poder tomar la vista que ya se creó para la vista de encabezado y extenderla, en lugar de tener que volver a crear toda la vista del encabezado usted mismo.

Aquí hay un ejemplo que colorea la sección del encabezado según un BOOL y agrega un elemento de texto detallado al encabezado.

- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
{
//    view.tintColor = [UIColor colorWithWhite:0.825 alpha:1.0]; // gray
//    view.tintColor = [UIColor colorWithRed:0.825 green:0.725 blue:0.725 alpha:1.0]; // reddish
//    view.tintColor = [UIColor colorWithRed:0.925 green:0.725 blue:0.725 alpha:1.0]; // pink

    // Conditionally tint the header view
    BOOL isMyThingOnOrOff = [self isMyThingOnOrOff];

    if (isMyThingOnOrOff) {
        view.tintColor = [UIColor colorWithRed:0.725 green:0.925 blue:0.725 alpha:1.0];
    } else {
        view.tintColor = [UIColor colorWithRed:0.925 green:0.725 blue:0.725 alpha:1.0];
    }

    /* Add a detail text label (which has its own view to the section header… */
    CGFloat xOrigin = 100; // arbitrary
    CGFloat hInset = 20;
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(xOrigin + hInset, 5, tableView.frame.size.width - xOrigin - (hInset * 2), 22)];

    label.textAlignment = NSTextAlignmentRight;

    [label setFont:[UIFont fontWithName:@"Helvetica-Bold" size:14.0]
    label.text = @"Hi.  I'm the detail text";

    [view addSubview:label];
}
Alex Zavatone
fuente
0

Swift 4.2

En Swift 4.2, el nombre de la tabla ha cambiado un poco.

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let view = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 18))
        let label = UILabel(frame: CGRect(x: 10, y: 5, width: tableView.frame.size.width, height: 18))
        label.font = UIFont.systemFont(ofSize: 14)
        label.text = list.objectAtIndex(section) as! String
        view.addSubview(label)
        view.backgroundColor = UIColor.gray // Set your background color

        return view
    }
Esmaeil
fuente