Как реализовать пользовательскую таблицу представления таблицы Заголовки и нижние колонтитулы с раскадровки
Без использования раскадровки мы могли бы просто перетащить UIView
на холст, выложить его, а затем установить в методах делегата tableView:viewForHeaderInSection
или tableView:viewForFooterInSection
.
Как это сделать с помощью StoryBoard, где мы не можем перетащить UIView на холст
Ответы
Ответ 1
Просто используйте ячейку прототипа в качестве заголовка раздела и/или нижнего колонтитула.
- добавьте дополнительную ячейку и поместите в нее нужные элементы.
- установить идентификатор для чего-то конкретного (в моем случае SectionHeader)
- реализовать метод
tableView:viewForHeaderInSection:
или метод tableView:viewForFooterInSection:
- используйте
[tableView dequeueReusableCellWithIdentifier:]
, чтобы получить заголовок
- реализовать метод
tableView:heightForHeaderInSection:
.
![(see 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;
}
Изменить: Как изменить заголовок заголовка (комментарий):
- Добавить метку в ячейку заголовка
- установите метку метки на конкретный номер (например, 123)
- В вашем методе
tableView:viewForHeaderInSection:
получите метку, вызвав:
UILabel *label = (UILabel *)[headerView viewWithTag:123];
- Теперь вы можете использовать метку для установки нового названия:
[label setText:@"New Title"];
Ответ 2
Я знаю, что этот вопрос был для iOS 5, но для будущих читателей обратите внимание, что эффективный iOS 6 теперь можно использовать dequeueReusableHeaderFooterViewWithIdentifier
вместо dequeueReusableCellWithIdentifier
.
Итак, в viewDidLoad
вызовите либо registerNib:forHeaderFooterViewReuseIdentifier:
, либо registerClass:forHeaderFooterViewReuseIdentifier:
. Затем в viewForHeaderInSection
вызовите tableView:dequeueReusableHeaderFooterViewWithIdentifier:
. Вы не используете прототип ячейки с этим API (это либо представление на основе NIB, либо программно созданное представление), но это новый API для перечеркнутых верхних и нижних колонтитулов.
Ответ 3
В iOS 6.0 и выше все изменилось с помощью нового API dequeueReusableHeaderFooterViewWithIdentifier
.
Я написал guide (проверенный на iOS 9), который можно суммировать следующим образом:
- Подкласс
UITableViewHeaderFooterView
- Создайте Nib с видом подкласса и добавьте 1 вид контейнера, который содержит все другие представления в верхнем/нижнем колонтитуле
- Зарегистрируйте Nib в
viewDidLoad
- Внедрите
viewForHeaderInSection
и используйте dequeueReusableHeaderFooterViewWithIdentifier
, чтобы вернуть верхний/нижний колонтитул
Ответ 4
Я получил его в iOS7, используя прототип ячейки в раскадровке. У меня есть кнопка в моем заголовке заголовка пользовательского раздела, который запускает segue, который настроен в раскадровке.
Начните с решения Tieme
Как указывает Pedro.m, проблема заключается в том, что нажатие на заголовок секции вызывает выбор первой ячейки в секции.
Как указывает Пол Вон, это фиксируется возвратом содержимого cellView вместо всей ячейки.
Однако, как отмечает Hons, длительное нажатие на заголовок секции приведет к сбою приложения.
Решение состоит в том, чтобы удалить любые указатели gestureRecognizers из 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; }
Если вы не используете жесты в своих заголовках заголовков разделов, этот небольшой взлом, похоже, все-таки делается.
Ответ 5
Если вы используете раскадровки, вы можете использовать ячейку прототипа в представлении tableview для компоновки вашего заголовка. Установите уникальный идентификатор и viewForHeaderInSection, вы можете удалить ячейку с этим идентификатором и передать его в UIView.
Ответ 6
Решение, которое я придумал, в основном такое же решение, которое использовалось до внедрения раскадровки.
Создайте новый пустой файл класса интерфейса. Перетащите UIView на холст, по желанию.
Загрузите ручку вручную, назначьте соответствующий раздел заголовка/нижнего колонтитула в методах делегата viewForHeaderInSection или viewForFooterInSection.
У меня была надежда, что Apple упростила этот сценарий с помощью раскадровки и продолжала искать лучшее или более простое решение. Например, пользовательские заголовки таблиц и нижние колонтитулы прямо добавляются.
Ответ 7
Если вам нужна быстрая реализация, следуйте инструкциям принятого ответа, а затем в UITableViewController реализуйте следующие методы:
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
}
Ответ 8
Когда вы возвращаете элемент содержимого CellView, у вас будет две проблемы:
- авария, связанная с жестов
- вы не повторно используете contentView (каждый раз при вызове
viewForHeaderInSection
, вы создаете новую ячейку)
Решение:
Класс обертки для заголовка таблицы \footer.
Это просто контейнер, унаследованный от UITableViewHeaderFooterView
, который содержит ячейку внутри
https://github.com/Magnat12/MGTableViewHeaderWrapperView.git
Зарегистрируйте класс в вашем UITableView (например, в viewDidLoad)
- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView registerClass:[MGTableViewHeaderWrapperView class] forHeaderFooterViewReuseIdentifier:@"ProfileEditSectionHeader"];
}
В 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;
}
Ответ 9
Я делал следующее, чтобы создавать заголовки/нижние колонтитулы лениво:
- Добавить контроллер представления формы для заголовка/нижнего колонтитула раздела в раскадровку
- Обрабатывать все содержимое заголовка в контроллере представления.
- В контроллере табличного представления предусмотрены изменяемые массивы контроллеров представлений для заголовков/нижних колонтитулов раздела, заполненных с помощью
[NSNull null]
- В viewForHeaderInSection/viewForFooterInSection, если диспетчер представлений еще не существует, создайте его с помощью storyboardsViewControllerWithIdentifier, запомните его в массиве и верните представление диспетчера представлений
Ответ 10
Вы должны использовать решение Tieme в качестве базы, но забудьте о viewWithTag:
и других подозрительных подходах, вместо этого попробуйте перезагрузить свой заголовок (перезагрузив этот раздел).
Итак, после того, как вы собрали свой собственный заголовок сокета со всеми причудливыми вещами AutoLayout
, просто удалите его и верните contentView после вашей настройки, например:
-(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;
}
Ответ 11
Чтобы следить за предложением Damon, вот как я сделал заголовок, который можно выбрать, как обычную строку с индикатором раскрытия.
Я добавил подклассу Button из UIButton (имя подкласса "ButtonWithArgument" ) в ячейку прототипа заголовка и удалил текст заголовка (полужирный текст "Заголовок" - это еще один UILabel в ячейке прототипа)
![Button In Interface Builder]()
затем установите кнопку на весь вид заголовка и добавили индикатор раскрытия с трюком 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]];
}
// /questions/39988/how-to-implement-custom-table-view-section-headers-and-footers-with-storyboard/289535#289535
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];
// /questions/25248/use-table-view-disclosure-indicator-style-for-uibutton-ios/184054#184054
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
Ответ 12
Вот @Ответ Виталия Гоженко, в Свифт.
В итоге вы создадите UITableViewHeaderFooterView, который содержит UITableViewCell. Этот UITableViewCell будет "dequeuable", и вы можете его спроектировать в своем раскадровке.
-
Создайте класс 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)
}
}
}
-
Подключите свой Tableview к этому классу в функции viewDidLoad:
self.tableView.registerClass(CustomHeaderFooterView.self, forHeaderFooterViewReuseIdentifier: "SECTION_ID")
-
При запросе заголовка раздела удалите CustomHeaderFooterView и вставьте в него ячейку
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;
}
Ответ 13
У меня были проблемы в сценарии, где Header никогда не использовался повторно, даже делая все необходимые шаги.
Итак, в качестве примечания для всех, кто хочет достичь ситуации появления пустых разделов (0 строк), следует предупредить, что:
dequeueReusableHeaderFooterViewWithIdentifier не будет повторно использовать заголовок, пока вы не вернете хотя бы одну строку
Надеюсь, что это поможет
Ответ 14
Как насчет решения, в котором заголовок основан на массиве вида:
class myViewController: UIViewController {
var header: [UILabel] = myStringArray.map { (thisTitle: String) -> UILabel in
let headerView = UILabel()
headerView.text = thisTitle
return(headerView)
}
Далее в делегате:
extension myViewController: UITableViewDelegate {
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return(header[section])
}
}
Ответ 15
-
Добавьте ячейку в StoryBoard
и установите reuseidentified
![sb]()
-
Код
class TP_TaskViewTableViewSectionHeader: UITableViewCell{
}
и
![link]()
-
Применение:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = tableView.dequeueReusableCell(withIdentifier: "header", for: IndexPath.init(row: 0, section: section))
return header
}