webentwicklung-frage-antwort-db.com.de

Wie verwende ich UITableViewHeaderFooterView?

Hallo, ich möchte UITableHeaderFooterView in meiner App verwenden und mache folgendes:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    [_tableView registerClass:[M3CTableViewCell class] forCellReuseIdentifier:@"cell"];
    [_tableView registerClass:[M3CHeaderFooter class] forHeaderFooterViewReuseIdentifier:@"footer"];

}

- (UITableViewHeaderFooterView *)footerViewForSection:(NSInteger)section {
    M3CHeaderFooter * footer = [[M3CHeaderFooter alloc]initWithReuseIdentifier:@"footer"];
    footer.textLabel.text = @"Test";
    return footer;
}

Auf diese Weise bekomme ich nichts bei Footer ... Und diese Methode wird nicht einmal aufgerufen, aber ich denke, diese Methode ist Teil des UITableViewDelegate-Protokolls.

45
Ashutosh

Die Verwendung der neuen iOS 6-Funktion für wiederverwendbare Kopf-/Fußzeilenansichten umfasst zwei Schritte. Sie scheinen nur den ersten Schritt zu tun.

Erster Schritt: Sie sagen der Tabellenansicht, welche Klasse für die Ansicht des Abschnittskopfs verwendet werden soll, indem Sie Ihre benutzerdefinierte Unterklasse von UITableViewHeaderFooterView registrieren (ich nehme an, Ihr M3CHeaderFooter ist eine Unterklasse von UITableViewHeaderFooterView). 

Zweiter Schritt: Sagen Sie der Tabellensicht, welche Ansicht für einen Headerabschnitt verwendet werden soll (AND-Wiederverwendung), indem Sie die Delegierungsmethode tableView implementieren

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

In viewDidLoad würden Sie also Folgendes implementieren:

    // ****** Do Step One ******
    [_tableView registerClass:[M3CHeaderFooter class] forHeaderFooterViewReuseIdentifier:@"TableViewSectionHeaderViewIdentifier"];

Dann implementieren Sie die Delegierte-Methode für die Tabellenansicht in der Klasse, in der Sie Ihre Tabellenansicht erstellen und anzeigen:

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return 40.0;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    static NSString *headerReuseIdentifier = @"TableViewSectionHeaderViewIdentifier";

    // ****** Do Step Two *********
    M3CHeaderFooter *sectionHeaderView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:headerReuseIdentifier];
   // Display specific header title
   sectionHeaderView.textLabel.text = @"specific title";   

    return sectionHeaderView;    
}

Bedenken Sie jedoch, dass Sie UITableViewHeaderFooterView nicht für die Verwendung in UITableViewHeaderFooterView verwenden müssen .. Wenn Sie vor iOS 6 eine Header-Ansicht für einen Abschnitt haben möchten, implementieren Sie die oben genannte tableView-Delegatenmethode und teilen die Tabellenansicht mit welche Ansicht für jeden Abschnitt verwendet werden soll. Jeder Abschnitt hatte also eine andere Instanz eines UIView, die Sie zur Verfügung gestellt haben. Das bedeutet, wenn Ihre tableView 100 Abschnitte hat und Sie innerhalb der Delegate-Methode eine neue Instanz von UIView erstellt haben, hätten Sie den tableView 100 UIViews für die 100 angezeigten Abschnittsheader gegeben. 

Mit der neuen Funktion wiederverwendbarer Kopf-/Fußzeilenansichten erstellen Sie eine Instanz von UITableViewHeaderFooterView, die vom System für jeden angezeigten Abschnittsheader verwendet wird.

Wenn Sie eine wiederverwendbare UITableViewHeaderFooterView ohne Unterklassifizierung wünschen, ändern Sie einfach viewDidLoad wie folgt:

// Register the class for a header view reuse.
[_buttomTableView registerClass:[UITableViewHeaderFooterView class] forHeaderFooterViewReuseIdentifier:@"TableViewSectionHeaderViewIdentifier"];

und dann deine Delegatmethode dazu:

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return 40.0;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    static NSString *headerReuseIdentifier = @"TableViewSectionHeaderViewIdentifier";

   // Reuse the instance that was created in viewDidLoad, or make a new one if not enough.
    UITableViewHeaderFooterView *sectionHeaderView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:headerReuseIdentifier];
    sectionHeaderView.textLabel.text = @"Non subclassed header";

    return sectionHeaderView;

}

Ich hoffe das war klar genug.

EDIT: Wenn Sie die Header-Ansicht subclassieren, können Sie Code ähnlich dem folgenden implementieren, wenn Sie der HeaderView eine benutzerdefinierte Ansicht hinzufügen möchten:

        // Add any optional custom views of your own
    UIView *customView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 50.0, 30.0)];
    [customView setBackgroundColor:[UIColor blueColor]];

    [sectionHeaderView.contentView addSubview:customView];

Wenn Sie dies in der Unterklasse tun (im Gegensatz zur viewForHeaderInSection: delegate-Methode (wie unten von Matthias angegeben)), wird sichergestellt, dass nur eine Instanz von Unteransichten erstellt wird. Sie können dann innerhalb der Unterklasse beliebige Eigenschaften hinzufügen, über die Sie auf Ihre benutzerdefinierte Untersicht zugreifen können.

68
Raz

UITableViewHeaderFooterView ist eine der wenigen Stellen, an denen ich die Ansicht programmgesteuert handhaben würde, anstatt das Storyboard oder eine XIB zu verwenden. Da Sie das Aussehensproxy nicht offiziell verwenden können, gibt es keine IB-Methode, um UITableViewCells zu missbrauchen. Ich mache es auf altmodische Weise und benutze einfach das Tag auf dem Etikett, um die benutzerdefinierten Elemente abzurufen. 

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    UITableViewHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:kSectionHeaderReuseIdentifier];
    if (headerView == nil) {
        [tableView registerClass:[UITableViewHeaderFooterView class] forHeaderFooterViewReuseIdentifier:kSectionHeaderReuseIdentifier];
        headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:kSectionHeaderReuseIdentifier];
    }

    UILabel *titleLabel = (UILabel *)[headerView.contentView viewWithTag:1];
    if (titleLabel == nil) {
        UIColor *backgroundColor = [UIColor blackColor];
        headerView.contentView.backgroundColor = backgroundColor;
        titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(10.0f, 0.0f, 300.0f, 44.0f)];
        titleLabel.textColor = [UIColor whiteColor];
        titleLabel.backgroundColor = backgroundColor;
        titleLabel.shadowOffset = CGSizeMake(0.0f, 0.0f);
        titleLabel.tag = 1;
        titleLabel.font = [UIFont systemFontOfSize:24.0f];
        [headerView.contentView addSubview:titleLabel];
    }

    NSString *sectionTitle = [self.sections objectAtIndex:section];
    if (sectionTitle == nil) {
        sectionTitle = @"Missing Title";
    }

    titleLabel.text = sectionTitle;

    return headerView;
}

Dies ist ein alter Beitrag und hat gute Antworten, aber ich wollte ein weiteres Problem umgehen, um ein sehr ähnliches Problem zu lösen, das ich erlebt habe.

Zuerst habe ich verwendet:

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

Mit einer benutzerdefinierten Prototypzelle für meine Kopfansicht. Unterklasse UITableViewCell als solche

    static NSString *cellIdentifier = @"CustomHeaderCell";
CustomHeaderCell * cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

Wenn Sie TableView-Zellen oberhalb der Abschnittskopfzeilen animieren (wodurch sie doppelt so groß sind), wird die Kopfansicht nicht mehr angezeigt. Wie bereits erwähnt, liegt dies daran, dass die Implementierung nur eine Ansicht und keine wiederverwendbare Ansicht lieferte. 

Anstatt auf die angepasste Prototypzelle zu verzichten, implementierte ich den UITableViewHeaderFooterWithIdentifier und stellte ihn als contentView der Zelle des Prototyps ein, ohne UITableViewHeaderFooterWithIdentifier zu subklassifizieren.

  static NSString *customHeaderViewIdentifier = @"CustomHeaderView";
UITableViewHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:customHeaderViewIdentifier];

headerView = (UITableViewHeaderFooterView *)cell.contentView;

Mir ist klar, dass dadurch zwei Instanzen der Kopfzeilenansicht erstellt werden (zumindest denke ich, dass dies der Fall wäre.). Sie können jedoch die Vorteile einer angepassten Prototypzelle beibehalten, ohne alles programmgesteuert zu machen.

Vollständiger Code:

  // viewDidLoad
    [myTableView registerClass:[UITableViewHeaderFooterView class] forHeaderFooterViewReuseIdentifier:@"CustomHeaderView"];

// Implement your custom header
 -(UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
     static NSString *cellIdentifier = @"CustomHeaderCell";
    CustomHeaderCell * cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

    static NSString *customHeaderViewIdentifier = @"CustomHeaderView";
    UITableViewHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:customHeaderViewIdentifier];

// do your cell-specific code here
// eg. cell.myCustomLabel.text = @"my custom text"

    headerView = (UITableViewHeaderFooterView *)cell.contentView;

return headerView;
}
7
EricK

Es gibt einige Wege, um dies zu erreichen, aber hier ist eine Lösung in Swift : Die Idee hier ist, dass wir eine Unterklasse von UITableViewHeaderFooterView haben, die SNStockPickerTableHeaderView genannt wird. Es macht eine Methode mit dem Namen configureTextLabel() verfügbar, die beim Aufruf die Schriftart und die Farbe der Textbeschriftung festlegt. Wir rufen diese Methode nur auf, nachdem der Titel festgelegt wurde, dh willDisplayHeaderView, und die Schriftart richtig eingestellt ist. 

Die Kopfansicht unterstützt auch ein benutzerdefiniertes Zeilentrennzeichen, um es von den restlichen Zellen zu unterscheiden.

// MARK: UITableViewDelegate

func tableView(tableView:UITableView, willDisplayHeaderView view:UIView, forSection section:Int) {
  if let headerView:SNStockPickerTableHeaderView = view as? SNStockPickerTableHeaderView {
    headerView.configureTextLabel()
  }
}

func tableView(tableView:UITableView, viewForHeaderInSection section:Int) -> UIView? {
  var headerView:SNStockPickerTableHeaderView? = tableView.dequeueReusableHeaderFooterViewWithIdentifier(kSNStockPickerTableHeaderViewReuseIdentifier) as? SNStockPickerTableHeaderView
  if (headerView == nil) {
    // Here we get to customize the section, pass in background color, text 
    // color, line separator color, etc. 
    headerView = SNStockPickerTableHeaderView(backgroundColor:backgroundColor,
      textColor:primaryTextColor,
      lineSeparatorColor:primaryTextColor)
  }
  return headerView!
}

Und hier ist die benutzerdefinierte UITableViewHeaderFooterView:

import Foundation
import UIKit

private let kSNStockPickerTableHeaderViewLineSeparatorHeight:CGFloat = 0.5
private let kSNStockPickerTableHeaderViewTitleFont = UIFont(name:"HelveticaNeue-Light", size:12)

let kSNStockPickerTableHeaderViewReuseIdentifier:String = "stock_picker_table_view_header_reuse_identifier"

class SNStockPickerTableHeaderView: UITableViewHeaderFooterView {

  private var lineSeparatorView:UIView?
  private var textColor:UIColor?

  required init(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  // We must implement this, since the designated init of the parent class
  // calls this by default!
  override init(frame:CGRect) {
    super.init(frame:frame)
  }

  init(backgroundColor:UIColor, textColor:UIColor, lineSeparatorColor:UIColor) {
    super.init(reuseIdentifier:kSNStockPickerTableHeaderViewReuseIdentifier)
    contentView.backgroundColor = backgroundColor
    self.textColor = textColor
    addLineSeparator(textColor)
  }

  // MARK: Layout

  override func layoutSubviews() {
    super.layoutSubviews()
    let lineSeparatorViewY = CGRectGetHeight(self.bounds) - kSNStockPickerTableHeaderViewLineSeparatorHeight
    lineSeparatorView!.frame = CGRectMake(0,
      lineSeparatorViewY,
      CGRectGetWidth(self.bounds),
      kSNStockPickerTableHeaderViewLineSeparatorHeight)
  }

  // MARK: Public API

  func configureTextLabel() {
    textLabel.textColor = textColor
    textLabel.font = kSNStockPickerTableHeaderViewTitleFont
  }

  // MARK: Private

  func addLineSeparator(lineSeparatorColor:UIColor) {
    lineSeparatorView = UIView(frame:CGRectZero)
    lineSeparatorView!.backgroundColor = lineSeparatorColor
    contentView.addSubview(lineSeparatorView!)
  }
}

Hier ist das Ergebnis, siehe Abschnittkopf für "Beliebte Aktien":

enter image description here

5
Zorayr

Ich kann nicht unter Cameron Lowell Palmer post kommentieren, aber um Christopher King zu antworten, gibt es eine einfache Möglichkeit, die Wiederverwendung sicherzustellen, ohne UITableViewHeaderFooterView zu klassifizieren und benutzerdefinierte Subviews zu verwenden.

Registrieren Sie die Klasse NICHT für eine Wiederverwendung der Kopfansicht.

Dann in tableView: viewForHeaderInSection: Sie müssen bei Bedarf einfach UITableViewHeaderFooterView erstellen:

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

    UILabel *titleLabel = nil;

    UITableViewHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:kYourTableViewReusableHeaderIdentifier];

    if (headerView == nil) {

        headerView = [[UITableViewHeaderFooterView alloc] initWithReuseIdentifier:kYourTableViewReusableHeaderIdentifier];

        titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(...)];
        titleLabel.tag = 1;
        // ... setup titleLabel 

        [headerView.contentView addSubview:titleLabel];
    } else {
        // headerView is REUSED
        titleLabel = (UILabel *)[headerView.contentView viewWithTag:1];
    }

    NSString *sectionTitle = (...); // Fetch value for current section
    if (sectionTitle == nil) {
        sectionTitle = @"Missing Title";
    }

    titleLabel.text = sectionTitle;

    return headerView;
}
3
Bluezen

Hier ist eine "schnelle und schmutzige" Möglichkeit, dies in Gang zu bringen. In der Kopfzeile wird ein kleines blaues Etikett angezeigt. Ich habe bestätigt, dass dies in iOS 6 und iOS 7 in Ordnung ist.

in Ihrem UITableViewDelegate:

 -(void)viewDidLoad
{
...
    [self.table registerClass:[UITableViewHeaderFooterView class] forHeaderFooterViewReuseIdentifier:@"Header"];
...
}

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

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    UITableViewHeaderFooterView *header = [tableView dequeueReusableHeaderFooterViewWithIdentifier:@"Header"];

    UILabel *leftlabel = [[UILabel alloc] initWithFrame:CGRectMake(0., 0., 400., 34.)];
    [leftlabel setBackgroundColor:[UIColor blueColor]];

    [header.contentView addSubview:leftlabel];
    return header;
}
1
maz

Falls es in den obigen ausführlichen Antworten verloren geht, werden Personen (im Vergleich zur Standardmethode cellForRowAtIndexPath:) wahrscheinlich vermisst, dass Sie die für den Abschnittskopf verwendete Klasse registrieren müssen.

[tableView registerClass:[UITableViewHeaderFooterView class] forHeaderFooterViewReuseIdentifier:@"SectionHeader"];

Versuchen Sie, registerClass:forHeaderFooterViewReuseIdentifier: hinzuzufügen, und sehen Sie, ob es funktioniert.

0
pkamb

Ein Grund dafür, dass die Methode möglicherweise nicht aufgerufen wird, ist der Stil der Tabelle. Standard vs Grouped behandelt Kopf-/Fußzeilen unterschiedlich. Das könnte erklären, warum es nicht angerufen wird.

0
MarqueIV