Как использовать UITableViewHeaderFooterView?
Привет, я хочу использовать UITableHeaderFooterView в своем приложении, и я делаю это:
- (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;
}
Сделав это, я ничего не получаю в Footer.
И этот метод даже не вызван, но я думаю, что этот метод является частью протокола UITableViewDelegate.
Пожалуйста, помогите!
Ответы
Ответ 1
Использование новой функции iOS 6 для многоразового просмотра заголовка/нижнего колонтитула включает в себя два шага. Кажется, вы делаете только первый шаг.
Первый шаг: вы сообщаете таблице, какой класс следует использовать для представления заголовка раздела, зарегистрировав свой подклас UITableViewHeaderFooterView (я предполагаю, что ваш M3CHeaderFooter является подклассом UITableViewHeaderFooterView).
Второй шаг: скажите в таблице представление о том, какой вид использовать (и повторное использование) для раздела заголовка, реализуя метод делегирования tableView
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
Итак, в вашем представленииDidLoad вы реализуете что-то вроде этого:
// ****** Do Step One ******
[_tableView registerClass:[M3CHeaderFooter class] forHeaderFooterViewReuseIdentifier:@"TableViewSectionHeaderViewIdentifier"];
Затем вы должны реализовать метод представления вида таблицы View в классе, в котором вы создаете и отображаете представление в таблице:
- (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;
}
Теперь помните, что вам не нужно подклассифицировать UITableViewHeaderFooterView, чтобы использовать его.
Перед iOS 6, если вы хотите иметь представление заголовка для раздела, вы должны реализовать вышеупомянутый метод делегата tableView и сообщить таблице, какой вид использовать для каждого раздела. Поэтому у каждого раздела был другой экземпляр UIView, который вы предоставили. Это означает, что если ваш tableView имел 100 разделов, а внутри метода делегата вы создали новый экземпляр UIView, то вы предоставили tableView 100 UIViews для 100 заголовков разделов, которые были отображены.
Используя новую функцию многоразового просмотра заголовка/нижнего колонтитула, вы создаете экземпляр UITableViewHeaderFooterView, и система повторно использует его для каждого отображаемого заголовка раздела.
Если вы хотите иметь повторно используемый UITableViewHeaderFooterView без подкласса, вы просто меняете свой viewDidLoad на это:
// Register the class for a header view reuse.
[_buttomTableView registerClass:[UITableViewHeaderFooterView class] forHeaderFooterViewReuseIdentifier:@"TableViewSectionHeaderViewIdentifier"];
а затем ваш метод делегирования:
- (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;
}
Надеюсь, это было достаточно ясно.
EDIT: При подклассификации заголовка вы можете реализовать код, похожий на следующий, если вы хотите добавить пользовательское представление в headerView:
// 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];
Выполнение этого в подклассе, в отличие от метода viewForHeaderInSection: delegate (как указано ниже Matthias), обеспечит создание только одного экземпляра любых подзонов. Затем вы можете добавить любые свойства в подкласс, которые позволят вам получить доступ к вашему пользовательскому подзону.
Ответ 2
UITableViewHeaderFooterView - одно из немногих мест, которые я программно обрабатывал бы представление, а не использовал Storyboard или XIB. Поскольку вы не можете официально использовать внешний прокси-сервер, и нет никакого способа IB сделать это, не злоупотребляя UITableViewCells. Я делаю это по-старому и просто использую тег на ярлыке для извлечения пользовательских элементов.
- (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;
}
Ответ 3
Это старый пост и имеет хорошие ответы, но я хотел поделиться другим обходом для очень близкой проблемы, которую я испытал.
Сначала я использовал:
-(UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
С помощью специальной ячейки прототипа для моего заголовка. Подклассификация UITableViewCell как таковая
static NSString *cellIdentifier = @"CustomHeaderCell";
CustomHeaderCell * cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
Однако при анимации ячеек TableView над заголовками разделов (что делает их в два раза выше) заголовок будет исчезать. Это, как уже отмечалось, связано с тем, что реализация обеспечивала представление, а не повторное использование.
Вместо того, чтобы отказаться от всего с помощью специальной ячейки прототипа, я применил UITableViewHeaderFooterWithIdentifier и установил его как прототипированный элемент содержимого cellView без подкласса UITableViewHeaderFooterWithIdentifier.
static NSString *customHeaderViewIdentifier = @"CustomHeaderView";
UITableViewHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:customHeaderViewIdentifier];
headerView = (UITableViewHeaderFooterView *)cell.contentView;
Я понимаю, что это создает два экземпляра представления заголовка (по крайней мере, я думаю, что это будет...), однако это позволяет вам сохранять преимущества настраиваемой ячейки прототипа, не делая все программно.
Полный код:
// 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;
}
Ответ 4
Есть несколько способов приблизиться к этому, но вот одно из решений в Swift: идея состоит в том, что мы имеем подкласс UITableViewHeaderFooterView
, называемый SNStockPickerTableHeaderView
; он выставляет метод под названием configureTextLabel()
, который при вызове устанавливает шрифт и цвет текстовой метки. Мы называем этот метод только после того, как заголовок был установлен, т.е. От willDisplayHeaderView
, и шрифт правильно настроен.
В представлении заголовка также поддерживается отдельный разделитель строк, чтобы установить его отдельно от остальных ячеек.
// 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!
}
И вот пользовательский 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!)
}
}
Вот результат, см. заголовок раздела для "Популярные акции":
![enter image description here]()
Ответ 5
Я не могу комментировать сообщение Камерона Лоуэлла Палмера, но для ответа Кристофер Кинг есть простой способ обеспечить повторное использование без подкласса UITableViewHeaderFooterView и но все еще использует пользовательские подзаголовки.
Во-первых, НЕ регистрируйте класс для повторного использования вида заголовка.
Затем в tableView: viewForHeaderInSection: вам просто нужно создать UITableViewHeaderFooterView при необходимости:
-(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;
}
Ответ 6
Вот "быстрый и грязный" способ добиться этого. Он сделает маленькую синюю метку в заголовке. Я подтвердил, что это делает ОК в iOS 6 и iOS 7.
в 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;
}
Ответ 7
В случае, если он исчерпан в подробных ответах выше, то, что люди, вероятно, отсутствуют (по сравнению со стандартным методом cellForRowAtIndexPath:
), заключается в том, что вы должны зарегистрировать класс, используемый для заголовка раздела.
[tableView registerClass:[UITableViewHeaderFooterView class] forHeaderFooterViewReuseIdentifier:@"SectionHeader"];
Попробуйте добавить registerClass:forHeaderFooterViewReuseIdentifier:
и посмотреть, начнет ли он работать.
Ответ 8
Одна из причин, по которой метод не может быть вызван, - это стиль таблицы. Стандарт vs Grouped обрабатывает верхние и нижние колонтитулы по-разному. Это может объяснить, почему он не вызван.
Ответ 9
-
Задайте свойство delegate
экземпляра UITableView
для ссылки на контроллер, который реализует следующие методы:
-
Метод, который возвращает вид нижнего колонтитула раздела:
Запрос делегату для объекта представления для отображения в нижнем колонтитуле указанного раздела представления таблицы. - (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
-
Высота представления в нижнем колонтитуле раздела:
Предлагает делегату высоту использовать нижний колонтитул определенного раздела.
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:
раздел (NSInteger)