Можно ли отключить плавающие заголовки в 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 как объект возврата (который является вашим представлением заголовка). я сделал то же самое в своем коде