Можно ли отключить плавающие заголовки в UITableView с помощью UITableViewStylePlain?
Я использую страницы UITableView
для компоновки содержимого. Я использую заголовки табличного представления для компоновки определенных изображений и т.д., И я бы предпочел, чтобы они не плавали, но оставались статичными, как в случае, когда стиль установлен на UITableViewStyleGrouped
.
Другое, используя UITableViewStyleGrouped
, есть ли способ сделать это? Я бы хотел избежать группировки, поскольку он добавляет разницу по всем моим ячейкам и требует отключения фонового представления для каждой из ячеек. Я бы хотел полностью контролировать мой макет. В идеале они были бы "UITableViewStyleBareBones", но я не видел этого параметра в документах...
Большое спасибо,
Ответы
Ответ 1
Вы должны подделать это, используя специальную ячейку, чтобы делать ваши строки заголовков. Затем они будут прокручиваться, как любая другая ячейка в представлении таблицы.
Вам просто нужно добавить некоторую логику в cellForRowAtIndexPath
, чтобы вернуть правильный тип ячейки, когда это строка заголовка.
Вам, вероятно, придется самостоятельно управлять своими разделами, т.е. иметь все в одном разделе и подделывать заголовки. (Вы также можете попробовать вернуть скрытое представление для заголовка, но я не знаю, будет ли это работать)
Ответ 2
Скорее всего, это проще:
Objective-C:
CGFloat dummyViewHeight = 40;
UIView *dummyView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.tableView.bounds.size.width, dummyViewHeight)];
self.tableView.tableHeaderView = dummyView;
self.tableView.contentInset = UIEdgeInsetsMake(-dummyViewHeight, 0, 0, 0);
Swift:
let dummyViewHeight = CGFloat(40)
self.tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: self.tableView.bounds.size.width, height: dummyViewHeight))
self.tableView.contentInset = UIEdgeInsetsMake(-dummyViewHeight, 0, 0, 0)
Заголовки разделов теперь будут прокручиваться точно так же, как и любая обычная ячейка.
Ответ 3
(Для тех, кто когда-либо попадал сюда из-за неправильного стиля таблицы) Измените стиль таблицы с простого на сгруппированный, с помощью инспектора атрибутов или с помощью кода:
let tableView = UITableView(frame: .zero, style: .grouped)
Ответ 4
ПРЕДУПРЕЖДЕНИЕ: это решение реализует зарезервированный метод API. Это может помешать утверждению приложения Apple для распространения в AppStore.
Я описал частные методы, которые превращают заголовки разделов, плавающие в мой блог
В принципе, вам просто нужно подклассом UITableView
и вернуть NO
двумя способами:
- (BOOL)allowsHeaderViewsToFloat;
- (BOOL)allowsFooterViewsToFloat;
Ответ 5
Хорошо, я знаю, что поздно, но я должен был это сделать.
Я потратил 10 часов на поиски рабочего решения, но не нашел полного ответа. Нашел некоторые намеки, но трудно понять начинающим. Поэтому я должен был поставить свои 2 цента и выполнить ответ.
Как было предложено в нескольких ответах, единственным рабочим решением, которое я смог реализовать, является вставка нормальных ячеек в представление таблицы и обработка их как заголовков секций, но лучший способ добиться этого - вставить эти ячейки в строке 0 каждого раздела. Таким образом, мы можем легко справиться с этими настраиваемыми неплавающими заголовками.
Итак, шаги:
-
Внедрите UITableView со стилем UITableViewStylePlain.
-(void) loadView
{
[super loadView];
UITableView *tblView =[[UITableView alloc] initWithFrame:CGRectMake(0, frame.origin.y, frame.size.width, frame.size.height-44-61-frame.origin.y) style:UITableViewStylePlain];
tblView.delegate=self;
tblView.dataSource=self;
tblView.tag=2;
tblView.backgroundColor=[UIColor clearColor];
tblView.separatorStyle = UITableViewCellSeparatorStyleNone;
}
-
Реализовать titleForHeaderInSection как обычно (вы можете получить это значение, используя свою собственную логику, но я предпочитаю использовать стандартные делегаты).
- (NSString *)tableView: (UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSString *headerTitle = [sectionArray objectAtIndex:section];
return headerTitle;
}
-
Номер модификацииOfSectionsInTableView как обычно
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
int sectionCount = [sectionArray count];
return sectionCount;
}
-
Внедрение numberOfRowsInSection как обычно.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
int rowCount = [[cellArray objectAtIndex:section] count];
return rowCount +1; //+1 for the extra row which we will fake for the Section Header
}
-
Возвращает 0.0f в heightForHeaderInSection.
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 0.0f;
}
-
НЕ реализуйте viewForHeaderInSection. Удалите метод полностью вместо того, чтобы возвращать нуль.
-
В heightForRowAtIndexPath. Проверьте if (indexpath.row == 0) и верните желаемую высоту ячейки для заголовка раздела, иначе верните высоту ячейки.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row == 0)
{
return 80; //Height for the section header
}
else
{
return 70; //Height for the normal cell
}
}
-
Теперь в cellForRowAtIndexPath проверьте if (indexpath.row == 0) и реализуйте ячейку так, как вам нужен заголовок раздела, и установите для стиля выбора значение none. ELSE реализует ячейку, как вы хотите, чтобы нормальная ячейка была.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0)
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SectionCell"];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"SectionCell"] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone; //So that the section header does not appear selected
cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"SectionHeaderBackground"]];
}
cell.textLabel.text = [tableView.dataSource tableView:tableView titleForHeaderInSection:indexPath.section];
return cell;
}
else
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleGray; //So that the normal cell looks selected
cell.backgroundView =[[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"CellBackground"]]autorelease];
cell.selectedBackgroundView=[[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"SelectedCellBackground"]] autorelease];
}
cell.textLabel.text = [[cellArray objectAtIndex:indexPath.section] objectAtIndex:indexPath.row -1]; //row -1 to compensate for the extra header row
return cell;
}
}
-
Теперь реализуем willSelectRowAtIndexPath и возвращаем nil, если indexpath.row == 0. Это будет зависеть от того, что didSelectRowAtIndexPath никогда не запускается для строки заголовка раздела.
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0)
{
return nil;
}
return indexPath;
}
-
И, наконец, в файле didSelectRowAtIndexPath проверьте if (indexpath.row!= 0) и продолжайте.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row != 0)
{
int row = indexPath.row -1; //Now use 'row' in place of indexPath.row
//Do what ever you want the selection to perform
}
}
С этим вы закончили. Теперь у вас есть отлично прокручиваемый, неплавающий заголовок раздела.
Ответ 6
В своем построителе интерфейсов щелкните по вашей проблеме "Просмотр таблицы"
![просмотр таблицы задач]()
Затем перейдите к Attributes Inspector и смените Style Plain на Grouped
;) Легко
![easy]()
Ответ 7
Интересная вещь в UITableViewStyleGrouped заключается в том, что tableView добавляет стиль к ячейкам, а не к TableView.
Стиль добавляется как backgroundView в ячейки как класс UIGroupTableViewCellBackground, который обрабатывает рисунок другого фона в соответствии с положением ячейки в секции.
Поэтому очень простым решением будет использование UITableViewStyleGrouped, установка backgroundColor таблицы в clearColor и просто замена backgroundView ячейки в cellForRow:
cell.backgroundView = [[[UIView alloc] initWithFrame:cell.bounds] autorelease];
Ответ 8
Измените ваш стиль TableView:
self.tableview = [[UITableView alloc] initwithFrame:frame style:UITableViewStyleGrouped];
Согласно документации Apple для UITableView:
UITableViewStylePlain- Простой вид таблицы. Любые верхние или нижние колонтитулы отображаются в виде встроенных разделителей и плавают при прокрутке табличного представления.
UITableViewStyleGrouped- Представление таблицы, разделы которой представляют отдельные группы строк. Верхние и нижние колонтитулы раздела не плавают.
Ответ 9
Самый простой способ получить то, что вам нужно, - установить стиль таблицы как UITableViewStyleGrouped
,
стиль разделителя как UITableViewCellSeparatorStyleNone
:
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
return CGFLOAT_MIN; // return 0.01f; would work same
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
return [[UIView alloc] initWithFrame:CGRectZero];
}
Не пытайтесь просмотреть нижний колонтитул как nil
, не забудьте установить высоту заголовка и вид заголовка, после того как вы получите то, что вам нужно.
Ответ 10
Есть еще один сложный путь. Основная идея состоит в том, чтобы удвоить номер раздела, и первый показывает только заголовок, а второй показывает реальные ячейки.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return sectionCount * 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section%2 == 0) {
return 0;
}
return _rowCount;
}
Что нужно сделать, так это реализовать делегаты headerInSection:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
if (section%2 == 0) {
//return headerview;
}
return nil;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
if (section%2 == 0) {
//return headerheight;
}
return 0;
}
Этот подход также мало влияет на ваши источники данных:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
int real_section = (int)indexPath.section / 2;
//your code
}
Сравнивая с другими подходами, этот способ безопасен, не изменяя рамки или contentInsets таблицы.
Надеюсь, это может помочь.
Ответ 11
Хотя это может не решить вашу проблему, это было для меня, когда я хотел сделать подобное. Вместо установки заголовка я использовал нижний колонтитул раздела выше. Что меня спасло, так это то, что этот раздел был небольшим и статическим по своей природе, поэтому он никогда не прокручивался ниже нижней части обзора.
Ответ 12
Придумывая, как подойти к этой проблеме, я вспомнил очень важную информацию о UITableViewStyleGrouped.
Способ, которым UITableView реализует сгруппированный стиль (округленные границы вокруг ячеек), заключается в добавлении настраиваемого backgroundView в UITableViewCells, а не в UITableView. Каждая ячейка добавляет backgroundView в соответствии с ее положением в секции (верхние ряды получают верхнюю часть границы раздела, средние получают боковую границу, а нижняя часть - ну, нижняя часть).
Итак, если нам просто нужен простой стиль, и у нас нет пользовательского backgroundView для наших ячеек (что имеет место в 90% случаев), тогда все, что нам нужно сделать, это использовать UITableViewStyleGrouped и удалить настраиваемый фон. Это можно сделать, выполнив следующие два шага:
Измените наш стиль tableView на UITableViewStyleGrouped
Добавьте следующую строку в cellForRow, перед тем как вернуть ячейку:
cell.backgroundView = [[[UIView alloc] initWithFrame: cell.bounds] autorelease];
И вот оно. Стиль tableView станет точно таким же, как UITableViewStylePlain, за исключением плавающих заголовков.
Надеюсь, это поможет!
Ответ 13
Для Swift 3 +
Просто используйте UITableViewStyleGrouped
и установите высоту нижнего колонтитула равным нулю:
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return .leastNormalMagnitude
}
Ответ 14
Другой способ сделать это - сделать пустой раздел прямо перед тем, на который вы хотите включить заголовок, и поместить его в этот раздел. Поскольку раздел пуст, заголовок будет прокручиваться немедленно.
Ответ 15
Вы можете добавить один раздел (с нулевыми строками) выше, а затем установить вышеописанный разделFooterView в качестве текущего раздела headerView, footerView не плавает.
Надеюсь, что это поможет.
Ответ 16
Возможно, вы могли бы использовать scrollViewDidScroll
в таблицеView
и измените contentInset
на основе текущего видимого заголовка.
Кажется, что работает для моего использования!
extension ViewController : UIScrollViewDelegate{
func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard let tableView = scrollView as? UITableView,
let visible = tableView.indexPathsForVisibleRows,
let first = visible.first else {
return
}
let headerHeight = tableView.rectForHeader(inSection: first.section).size.height
let offset = max(min(0, -tableView.contentOffset.y), -headerHeight)
self.tableView.contentInset = UIEdgeInsetsMake(offset, 0, -offset, 0)
}
}
Ответ 17
Игнорировать XAK. Не изучайте какие-либо частные методы, если вы хотите, чтобы ваше приложение имело возможность принять яблоко.
Это проще всего, если вы используете Interface Builder. Вы должны добавить UIView в верхней части представления (куда будут идти изображения), а затем добавить таблицу ниже. IB должен соответствующим образом измерять его; то есть верхняя часть таблицы просматривает нижнюю часть UIView, которую вы только что добавили, и высота покрывает остальную часть экрана.
Мысль здесь состоит в том, что если этот UIView фактически не является частью представления таблицы, он не будет прокручиваться с помощью tableview. т.е. игнорировать заголовок таблицы.
Если вы не используете построитель интерфейсов, это немного сложнее, потому что вам нужно получить правильное позиционирование и высоту таблицы.
Ответ 18
Проверьте ответ, как реализовать заголовки с помощью StoryBoard: Представления заголовка таблицы в StoryBoards
Также обратите внимание, что если вы не реализуете
viewForHeaderInSection:(NSInteger)section
он не будет плавать, что именно вы хотите.
Ответ 19
Чтобы полностью удалить разделы заголовка плавающего раздела, вы можете сделать это:
- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
return [[UIView alloc] init];
}
return nil
не работает.
Чтобы отключить плавающие, но все еще отображаемые заголовки разделов, вы можете предоставить собственное представление с собственным поведением.
Ответ 20
Вариант решения @samvermette:
/// Allows for disabling scrolling headers in plain-styled tableviews
extension UITableView {
static let shouldScrollSectionHeadersDummyViewHeight = CGFloat(40)
var shouldScrollSectionHeaders: Bool {
set {
if newValue {
tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: bounds.size.width, height: UITableView.shouldScrollSectionHeadersDummyViewHeight))
contentInset = UIEdgeInsets(top: -UITableView.shouldScrollSectionHeadersDummyViewHeight, left: 0, bottom: 0, right: 0)
} else {
tableHeaderView = nil
contentInset = .zero
}
}
get {
return tableHeaderView != nil && contentInset.top == UITableView.shouldScrollSectionHeadersDummyViewHeight
}
}
}
Ответ 21
Это может быть достигнуто путем назначения заголовка вручную в методе viewDidLoad UITableViewController вместо использования делегата viewForHeaderInSection и heightForHeaderInSection. Например, в вашем подклассе UITableViewController вы можете сделать что-то вроде этого:
- (void)viewDidLoad {
[super viewDidLoad];
UILabel *headerView = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 0, 40)];
[headerView setBackgroundColor:[UIColor magentaColor]];
[headerView setTextAlignment:NSTextAlignmentCenter];
[headerView setText:@"Hello World"];
[[self tableView] setTableHeaderView:headerView];
}
Заголовок будет исчезать при прокрутке пользователя. Я не знаю, почему это работает так, но, похоже, он добивается того, что вы хотите сделать.
Ответ 22
Возможно, вы можете просто сделать прозрачный вид заголовка прозрачным:
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section {
view.tintColor = [UIColor clearColor];
}
Или примените его глобально:
[UITableViewHeaderFooterView appearance].tintColor = [UIColor clearColor];
Ответ 23
В соответствии с ответом @samvermette, я внедрил приведенный выше код в Swift, чтобы упростить для кодеров использование swift.
let dummyViewHeight = CGFloat(40)
self.tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: self.tableView.bounds.size.width, height: dummyViewHeight))
self.tableView.contentInset = UIEdgeInsetsMake(-dummyViewHeight, 0, 0, 0)
Ответ 24
У меня есть еще одно более простое решение, которое можно использовать без автозапуска и со всем, что сделано через XIB:
1/Поместите свой заголовок в представление таблицы, перетащив его непосредственно в таблицу.
2/В инспекторе размеров недавно созданного заголовка просто измените его автоопределение: вы должны оставить только верхние, левые и правые анкеры, а также заполнить по горизонтали.
![That's how it should be set for the header]()
Это должно сделать трюк!
Ответ 25
ссылка: fooobar.com/questions/44223/...
let tableView = UITableView(frame:.zero, style:.grouped)
Pluse
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if section == 0 {
return 40
}else{
tableView.sectionHeaderHeight = 0
}
return 0
}
Это помогло использовать пространство заголовка
Ответ 26
вы можете легко достичь этого, внедрив метод viewForHeaderInSection в класс делегата tableview. этот метод ожидает UIView как объект возврата (который является вашим представлением заголовка). я сделал то же самое в своем коде