Odpowiedzi:
Wiem, że to pytanie dotyczyło iOS 5, ale z korzyścią dla przyszłych czytelników zwróć uwagę, że efektywnego iOS 6 możemy teraz używać dequeueReusableHeaderFooterViewWithIdentifier
zamiast dequeueReusableCellWithIdentifier
.
Więc viewDidLoad
zadzwoń albo registerNib:forHeaderFooterViewReuseIdentifier:
albo registerClass:forHeaderFooterViewReuseIdentifier:
. Następnie viewForHeaderInSection
zadzwoń tableView:dequeueReusableHeaderFooterViewWithIdentifier:
. Nie używasz prototypu komórki z tym interfejsem API (jest to widok oparty na NIB lub widok utworzony programowo), ale jest to nowy interfejs API dla usuniętych z kolejki nagłówków i stopek.
Po prostu użyj prototypowej komórki jako nagłówka i / lub stopki sekcji.
tableView:viewForHeaderInSection:
metodę lub tableView:viewForFooterInSection:
metodę[tableView dequeueReusableCellWithIdentifier:]
aby uzyskać nagłówektableView:heightForHeaderInSection:
metodę.-(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;
}
Edycja: Jak zmienić tytuł nagłówka (skomentowane pytanie):
tableView:viewForHeaderInSection:
metodzie uzyskaj etykietę, dzwoniąc: UILabel *label = (UILabel *)[headerView viewWithTag:123];
[label setText:@"New Title"];
viewForHeaderInSection
metodzie (nie ma potrzeby dodawania żadnych niestandardowych UIViews).
dequeueReusableHeaderFooterViewWithIdentifier
został wprowadzony i jest teraz preferowany w stosunku do tej odpowiedzi. Ale użycie tego poprawnie wymaga teraz więcej kroków. Mam przewodnik @ samwize.com/2015/11/06/ ...
UITableViewCell
jako widoku nagłówka. Będziesz bardzo trudno debugować usterki wizualne - nagłówek czasami znika z powodu sposobu, w jaki komórki są usuwane z kolejki i będziesz szukał przez wiele godzin, dlaczego tak jest, dopóki nie zorientujesz się, UITableViewCell
że nie należy do UITableView
nagłówka.
W systemie iOS 6.0 i nowszym sytuacja uległa zmianie wraz z nowym dequeueReusableHeaderFooterViewWithIdentifier
interfejsem API.
Napisałem poradnik (testowany na iOS 9), który można podsumować następująco:
UITableViewHeaderFooterView
viewDidLoad
viewForHeaderInSection
i użyj, dequeueReusableHeaderFooterViewWithIdentifier
aby odzyskać nagłówek / stopkęMam to działające w iOS7 przy użyciu prototypowej komórki w scenorysie. Mam przycisk w moim niestandardowym widoku nagłówka sekcji, który wyzwala przepływ, który jest skonfigurowany w scenorysie.
Zacznij od rozwiązania Tieme
Jak wskazuje pedro.m, problem polega na tym, że dotknięcie nagłówka sekcji powoduje wybranie pierwszej komórki w sekcji.
Jak podkreśla Paul Von, problem ten rozwiązano, zwracając contentView komórki zamiast całej komórki.
Jednak, jak wskazuje Hons, długie naciśnięcie nagłówka sekcji spowoduje awarię aplikacji.
Rozwiązaniem jest usunięcie wszystkich gestówRecognizers 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łówków sekcji, wydaje się, że ten mały hack załatwia sprawę.
Jeśli potrzebujesz szybkiej implementacji tego, postępuj zgodnie ze wskazówkami dotyczącymi zaakceptowanej odpowiedzi, a następnie UITableViewController zaimplementuj następujące metody:
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return tableView.dequeueReusableCell(withIdentifier: "CustomHeader")
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 75
}
Rozwiązanie, które wymyśliłem, jest w zasadzie tym samym rozwiązaniem, które zastosowano przed wprowadzeniem storyboardów.
Utwórz nowy, pusty plik klasy interfejsu. Przeciągnij UIView na kanwę, układ według potrzeb.
Załaduj końcówkę ręcznie, przypisz do odpowiedniej sekcji nagłówka / stopki w metodach delegata viewForHeaderInSection lub viewForFooterInSection.
Miałem nadzieję, że Apple uprościło ten scenariusz dzięki scenorysom i szukał lepszego lub prostszego rozwiązania. Na przykład niestandardowe nagłówki i stopki tabel można łatwo dodać.
tableView:titleForHeaderInSection
, to jeden wiersz.
Kiedy zwrócisz contentView komórki, będziesz miał 2 problemy:
viewForHeaderInSection
dzwonisz, tworzysz nową komórkę)Rozwiązanie:
Klasa opakowania dla nagłówka \ stopki tabeli. To tylko odziedziczony pojemnik UITableViewHeaderFooterView
, w którym znajduje się komórka
https://github.com/Magnat12/MGTableViewHeaderWrapperView.git
Zarejestruj klasę w swoim 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;
}
Kiedyś wykonywałem następujące czynności, aby leniwie tworzyć widoki nagłówka / stopki:
[NSNull null]
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.
Tak więc jako wskazówka dla wszystkich, którzy chcą osiągnąć sytuację pokazania pustych sekcji (0 wierszy), ostrzegamy, że:
dequeueReusableHeaderFooterViewWithIdentifier nie użyje ponownie nagłówka, dopóki nie zwrócisz co najmniej jednego wiersza
Mam nadzieję, że to pomoże
Aby podążać za sugestią Damona , oto jak sprawiłem, że nagłówek można wybrać, tak jak zwykły wiersz ze wskaźnikiem ujawnienia.
Dodałem podklasę Button z UIButton (nazwa podklasy „ButtonWithArgument”) do prototypowej komórki nagłówka i usunąłem tekst tytułu (pogrubiony tekst „Tytuł” to kolejny UILabel w komórce prototypu)
następnie ustaw przycisk na cały widok nagłówka i dodaj wskaźnik ujawnienia ze sztuczką 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://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
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 ustawieniu niestandardowego widoku nagłówka komórki ze wszystkimi fantazyjnymi AutoLayout
rzeczami, po prostu usuń go z kolejki i zwróć contentView po konfiguracji, na przykład:
-(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;
}
A co z rozwiązaniem, w którym nagłówek jest oparty na tablicy widoku:
class myViewController: UIViewController {
var header: [UILabel] = myStringArray.map { (thisTitle: String) -> UILabel in
let headerView = UILabel()
headerView.text = thisTitle
return(headerView)
}
Następnie w delegacie:
extension myViewController: UITableViewDelegate {
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return(header[section])
}
}
Dodaj komórkę StoryBoard
i ustawreuseidentified
Kod
class TP_TaskViewTableViewSectionHeader: UITableViewCell{
}
i
Posługiwać się:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = tableView.dequeueReusableCell(withIdentifier: "header", for: IndexPath.init(row: 0, section: section))
return header
}
Podobny do odpowiedzi laszlo, ale możesz ponownie użyć tej samej komórki prototypowej zarówno dla komórek tabeli, jak i komórki nagłówka sekcji. Dodaj pierwsze dwie funkcje poniżej do swojej podklasy UIViewController
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableCell(withIdentifier: "DataCell") as! DataCell
cell.data1Label.text = "DATA KEY"
cell.data2Label.text = "DATA VALUE"
return cell
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 75
}
// Example of regular data cell dataDelegate to round out the example
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DataCell", for: indexPath) as! PlayerCell
cell.data1Label.text = "\(dataList[indexPath.row].key)"
cell.data2Label.text = "\(dataList[indexPath.row].value)"
return cell
}
Oto odpowiedź @Vitaliy Gozhenko w języku Swift.
Podsumowując, utworzysz UITableViewHeaderFooterView, który zawiera UITableViewCell. Ta UITableViewCell będzie „usuwalna” i można ją zaprojektować w swoim storyboardzie.
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)
}
}
}
Podłącz widok tabeli do tej klasy w funkcji viewDidLoad:
self.tableView.registerClass(CustomHeaderFooterView.self, forHeaderFooterViewReuseIdentifier: "SECTION_ID")
Pytając o nagłówek sekcji, usuń z kolejki CustomHeaderFooterView i wstaw 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;
}