Jak zaimplementować niestandardowe nagłówki sekcji widoku tabeli i stopki za pomocą Storyboard

Bez użycia storyboardu możemy po prostu przeciągnąć UIView Na płótno, rozłożyć je, a następnie ustawić w metodach delegowania tableView:viewForHeaderInSection lub tableView:viewForFooterInSection.

Jak możemy to osiągnąć za pomocą storyboardu, w którym nie możemy przeciągnąć UIView na płótno

Author: Kumar KL, 2012-02-10

15 answers

Wiem, że to pytanie dotyczyło iOS 5, ale z korzyścią dla przyszłych czytelników, zauważ, że skuteczny iOS 6 możemy teraz używać dequeueReusableHeaderFooterViewWithIdentifier zamiast dequeueReusableCellWithIdentifier.

Więc w viewDidLoad zadzwoń albo registerNib:forHeaderFooterViewReuseIdentifier: albo registerClass:forHeaderFooterViewReuseIdentifier:. Następnie w viewForHeaderInSection, wywołaj tableView:dequeueReusableHeaderFooterViewWithIdentifier:. Nie używasz prototypu komórki z tym API (jest to Widok oparty na NIB lub widok utworzony programowo), ale jest to nowe API dla usuniętych nagłówków i stopek.

 80
Author: Rob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-20 20:18:21

Po prostu użyj prototypowej komórki jako nagłówka sekcji i / lub stopki.

  • dodaj dodatkową komórkę i umieść w niej pożądane elementy.
  • ustaw identyfikator na coś konkretnego (w moim przypadku SectionHeader)
  • zaimplementuj metodę tableView:viewForHeaderInSection: lub metodę tableView:viewForFooterInSection:
  • użyj [tableView dequeueReusableCellWithIdentifier:], aby uzyskać nagłówek
  • wdrożyć metodę tableView:heightForHeaderInSection:.

(zobacz screenhot)

-(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;
}  

Edit: Jak zmienić tytuł nagłówka (skomentowane pytanie):

  1. Dodaj etykietę do komórki nagłówka
  2. ustaw znacznik etykiety na konkretny numer (np. 123)
  3. w metodzie tableView:viewForHeaderInSection: uzyskaj Etykietę wywołując:
    UILabel *label = (UILabel *)[headerView viewWithTag:123]; 
  1. Teraz możesz użyć etykiety, aby ustawić nowy tytuł:
    [label setText:@"New Title"];
 380
Author: Tieme,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-14 12:07:14

W systemie iOS 6.0 i nowszym wiele się zmieniło dzięki nowemu API dequeueReusableHeaderFooterViewWithIdentifier.

Napisałem przewodnik (testowany na iOS 9), który można podsumować jako taki:

  1. podklasa UITableViewHeaderFooterView
  2. Utwórz Nib z widokiem podklasy i dodaj 1 widok kontenera, który zawiera wszystkie inne widoki w nagłówku / stopce
  3. Zarejestruj stalówkę w viewDidLoad
  4. zaimplementuj viewForHeaderInSection i użyj dequeueReusableHeaderFooterViewWithIdentifier, aby odzyskać nagłówek / stopkę
 50
Author: samwize,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-07 11:10:55

Działa w iOS7 używając prototypowej komórki w storyboardzie. Mam przycisk w moim niestandardowym widoku nagłówka sekcji, który wyzwala segue, który jest skonfigurowany w storyboardzie.

Zacznij od rozwiązania Tieme ' a

Jako pedrom zwraca uwagę, że problem polega na tym, że stuknięcie nagłówka sekcji powoduje wybranie pierwszej komórki w sekcji.

Jak wskazuje Paul Von, naprawia się to zwracając zawartość komórki zamiast całości cell.

Jednak, jak podkreśla Hons, długie naciśnięcie nagłówka sekcji spowoduje awarię aplikacji.

Rozwiązaniem jest usunięcie gestureRecognizers z 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; }

Jeśli nie używasz gestów w widokach nagłówka sekcji, ten mały hack wydaje się to zrobić.

 21
Author: damon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:17:55

Jeśli używasz storyboardów, możesz użyć prototypowej komórki w widoku tableview do układania widoku nagłówka. Ustaw unikalny identyfikator i viewForHeaderInSection możesz usunąć komórkę z tym identyfikatorem i wrzucić ją do widoku UIView.

 14
Author: barksten,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-12 08:46:54

Rozwiązanie, które wymyśliłem, jest w zasadzie tym samym rozwiązaniem używanym przed wprowadzeniem storyboardów.

Utwórz nowy, pusty plik klasy interfejsu. Przeciągnij Widok UIView na obszar roboczy, układ według potrzeb.

Załaduj stalówkę ręcznie, Przypisz do odpowiedniej sekcji nagłówka/stopki w metodach viewforheaderinsection lub viewforfooterinsection delegate.

Miałem nadzieję, że Apple uprościło ten scenariusz za pomocą storyboardów i nadal szukało lepszego lub prostszego rozwiązania. Na przykład niestandardowe nagłówki tabel i stopki są proste do dodania.

 9
Author: Seamus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-11 15:58:19

Jeśli potrzebujesz szybkiej implementacji tego, postępuj zgodnie ze wskazówkami na zaakceptowanej odpowiedzi, a następnie w uitableviewcontroller zaimplementuj następujące metody:

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
}
 9
Author: JZ.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-31 06:28:19

Gdy zwrócisz contentView komórki będziesz miał 2 Problemy:

  1. awaria związana z gestami
  2. nie używasz ponownie contentView (za każdym razem przy viewForHeaderInSection wywołaniu tworzysz nową komórkę)

Rozwiązanie:

Klasa Wrapper dla nagłówka tabeli\footer. Jest to po prostu kontener, dziedziczony z UITableViewHeaderFooterView, który przechowuje komórkę wewnątrz

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

Zarejestruj klasę w UITableView (na przykład w viewDidLoad)

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

W Twoim 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;
}
 5
Author: Vitaliy Gozhenko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-14 12:18:02

Aby leniwie tworzyć widoki nagłówka/stopki, wykonałem następujące czynności:

  • Dodaj kontroler widoku freeform dla nagłówka / stopki sekcji do storyboardu
  • Obsługa wszystkich rzeczy dla nagłówka w kontrolerze widoku
  • w kontrolerze widoku tabeli podaj zmienną tablicę kontrolerów widoku dla nagłówków / stopek sekcji przepełnionych [NSNull null]
  • In viewForHeaderInSection / viewForFooterInSection jeśli kontroler widoku jeszcze nie istnieje, utwórz go za pomocą storyboardów instantiateViewControllerWithIdentifier, zapamiętaj go w tablicy i zwróć widok kontrolerów widoku
 2
Author: Vipera Berus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-19 10:58:12

Aby kontynuowaćsugestię Damona , Oto jak zrobiłem nagłówek do wyboru, tak jak normalny wiersz ze wskaźnikiem ujawnienia.

Dodałem przycisk podklasowany z UIButton (nazwa podklasy "ButtonWithArgument") do prototypowej komórki nagłówka i usunąłem tekst tytułu (pogrubiony tekst "Title" to kolejna Etykieta UILabel w prototypowej komórce)

Przycisk W Kreatorze Interfejsów

Następnie Ustaw przycisk do całego widoku nagłówka i dodaj wskaźnik ujawnienia z Avario ' s trick

- (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://stackoverflow.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://stackoverflow.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
 1
Author: MarkF,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:12

Powinieneś użyć rozwiązania Tieme jako bazy, ale zapomnij o viewWithTag: i innych podejrzanych podejściach, zamiast tego spróbuj przeładować nagłówek (przeładowując tę sekcję).

Więc po usiadł swój niestandardowy widok nagłówka komórki z wszystkich fantazyjnych AutoLayout rzeczy, po prostu dequeue go i zwraca contentView po skonfigurowaniu, jak:

-(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;
}  
 1
Author: Laszlo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:23

Miałem kłopoty w scenariuszu, w którym nagłówek nigdy nie został ponownie użyty, nawet wykonując wszystkie właściwe kroki.

Więc jako wskazówka dla wszystkich, którzy chcą osiągnąć sytuację Pokaż puste sekcje (0 wierszy) należy ostrzec, że:

DequeueReusableHeaderFooterViewWithidentifier nie użyje ponownie nagłówka, dopóki nie zwrócisz co najmniej jednego wiersza

Hope it helps

 1
Author: Juan Pedro Lozano,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-24 20:17:23

Co z rozwiązaniem, w którym nagłówek jest oparty na tablicy widoków:

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

Następny w delegacie:

extension myViewController: UITableViewDelegate {
    func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        return(header[section])
    }
}
 1
Author: CyrIng,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-12 03:55:24

Oto @Vitaliy Gozhenko ' s answer , in Swift.
Podsumowując, utworzysz UITableViewHeaderFooterView, który zawiera UITableViewCell. Ten UITableViewCell będzie "dequeuable" i możesz go zaprojektować w swoim storyboardzie.

  1. Utwórz klasę 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. Podłącz tableview z tą klasą w funkcji viewDidLoad:

    self.tableView.registerClass(CustomHeaderFooterView.self, forHeaderFooterViewReuseIdentifier: "SECTION_ID")
    
  3. Pytając o nagłówek sekcji, dequeue a CustomHeaderFooterView i wstawić do niego komórkę

    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;
    }
    
 0
Author: CedricSoubrie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:28
  1. Dodaj komórkę w StoryBoard i ustaw reuseidentified

    sb

  2. Kod

    class TP_TaskViewTableViewSectionHeader: UITableViewCell{
    }
    

    I

    link

  3. Użycie:

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let header = tableView.dequeueReusableCell(withIdentifier: "header", for: IndexPath.init(row: 0, section: section))
        return header
    }
    
 0
Author: leo.tan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-22 08:43:12