是否可以使用UITableViewStylePlain禁用UITableView中的浮动标题?

时间:2009-07-02 12:09:19

标签: ios objective-c iphone cocoa-touch uikit

我正在使用UITableView来布局内容“网页”。我正在使用表格视图的标题来布局某些图像等等。如果它们没有浮动,我会更喜欢它,但是当样式设置为UITableViewStyleGrouped时保持静态。

然后使用UITableViewStyleGrouped,有没有办法做到这一点?我想避免使用分组,因为它会在我的所有单元格中添加边距,并且需要禁用每个单元格的背景视图。我想完全控制我的布局。理想情况下,它们是“UITableViewStyleBareBones”,但我没有在文档中看到该选项......

非常感谢,

30 个答案:

答案 0 :(得分:303)

实现这一目标的更简单方法:

目标-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);

夫特:

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)

现在,节标题将像任何常规单元格一样滚动。

答案 1 :(得分:202)

(由于错误的表格样式而来到这里的人)将表格样式从普通变为分组,通过属性检查器或通过代码:

let tableView = UITableView(frame: .zero, style: .grouped)

答案 2 :(得分:70)

警告:此解决方案实现了保留的API方法。这可能会阻止Apple批准该应用在AppStore上发布。

我已经描述了在my blog

中浮动节标题的私有方法

基本上,您只需要在其两个方法中继承UITableView并返回NO

- (BOOL)allowsHeaderViewsToFloat;
- (BOOL)allowsFooterViewsToFloat;

答案 3 :(得分:28)

好的,我知道现在已经晚了但我不得不这样做。 我现在花了10个小时寻找一个有效的解决方案,但没有找到完整的答案。确实找到了一些提示但很难让初学者理解。所以我必须投入2美分并完成答案。

正如在少数答案中所建议的那样,我能够实现的唯一可行解决方案是在表视图中插入普通单元并将它们作为Section Headers处理,但实现它的更好方法是插入这些单元格位于每个部分的第0行。这样我们就可以非常轻松地处理这些自定义非浮动标题。

所以,步骤是。

  1. 使用UITableViewStylePlain样式实现UITableView。

    -(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;
    }
    
  2. 像往常一样实现titleForHeaderInSection(您可以使用自己的逻辑获取此值,但我更喜欢使用标准委托)。

    - (NSString *)tableView: (UITableView *)tableView titleForHeaderInSection:(NSInteger)section
    {
        NSString *headerTitle = [sectionArray objectAtIndex:section];
        return headerTitle;
    }
    
  3. 像往常一样填充numberOfSectionsInTableView

    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
    {
        int sectionCount = [sectionArray count];
        return sectionCount;
    }
    
  4. 像往常一样实施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
    }
    
  5. 在heightForHeaderInSection中返回0.0f。

    - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
    {
        return 0.0f;
    }
    
  6. 请勿实现viewForHeaderInSection。完全删除方法而不是返回nil。

  7. 在heightForRowAtIndexPath中。检查是否(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
        }
    }
    
  8. 现在在cellForRowAtIndexPath中,检查是否(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;
        }
    }
    
  9. 现在实现willSelectRowAtIndexPath并返回nil,如果indexpath.row == 0.这将关心didSelectRowAtIndexPath永远不会被截面标题行触发。

    - (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
        if (indexPath.row == 0)
        {
            return nil;
        }
    
        return indexPath;
    }
    
  10. 最后在didSelectRowAtIndexPath中,检查是否(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
        }
    }
    
  11. 有了这个,你就完成了。您现在拥有一个完美滚动的非浮动节标题。

答案 4 :(得分:25)

您应该可以通过使用自定义单元格来标记行。然后,它们将像表视图中的任何其他单元格一样滚动。

您需要在cellForRowAtIndexPath中添加一些逻辑,以便在标题行时返回正确的单元格类型。

你可能必须自己管理你的部分,即将所有内容放在一个部分中并伪造标题。 (您也可以尝试返回标题视图的隐藏视图,但我不知道这是否有效)

答案 5 :(得分:25)

在Interface Builder中,单击问题表视图

problem table view

然后导航到Attributes Inspector并将Style Plain更改为Grouped ;)轻松

easy

答案 6 :(得分:17)

UITableViewStyleGrouped的有趣之处在于tableView将样式添加到单元格而不是TableView。

将样式作为backgroundView添加到单元格中,作为一个名为UIGroupTableViewCellBackground的类,它根据单元格中单元格的位置处理不同的背景。

所以一个非常简单的解决方案是使用UITableViewStyleGrouped,将表的backgroundColor设置为clearColor,并简单地替换cellForRow中单元格的backgroundView:

cell.backgroundView = [[[UIView alloc] initWithFrame:cell.bounds] autorelease];

答案 7 :(得分:11)

更改TableView样式:

self.tableview = [[UITableView alloc] initwithFrame:frame style:UITableViewStyleGrouped];

根据UITableView的Apple文档:

  

UITableViewStylePlain-普通表视图。任何部分标题或   页脚显示为内联分隔符并在表格中浮动   视图滚动。

     

UITableViewStyleGrouped-一个表格视图,其截面显示不同   行组。部分页眉和页脚不会浮动。

希望这个小改变能帮到你..

答案 8 :(得分:5)

获得所需内容的最简单方法是将表格样式设置为test_that, 分隔符样式为expect_*

UITableViewStyleGrouped

请勿尝试以UITableViewCellSeparatorStyleNone的形式返回页脚视图,在您必须得到所需内容后,请不要忘记设置标题高度和标题视图。

答案 9 :(得分:5)

还有另一种棘手的方法。主要思想是将节号加倍,第一个只显示headerView,而第二个显示真实单元格。

- (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
}

与其他方法相比,这种方式是安全的,同时不会更改tableview的框架或contentInsets。 希望这可能有所帮助。

答案 10 :(得分:4)

虽然这可能无法解决您的问题,但当我想做类似的事情时,它确实适用于我。我没有设置标题,而是使用了上面部分的页脚。救了我的是这个部分本质上是小而静态的,所以它从不滚动到视图的底部以下。

答案 11 :(得分:3)

在思考如何解决这个问题时,我想起了一个关于UITableViewStyleGrouped的非常重要的细节。 UITableView实现分组样式(单元格周围的圆形边框)的方法是将自定义backgroundView添加到UITableViewCells,而不是UITableView。每个单元格根据其在截面中的位置添加一个backgroundView(上面的行得到部分边框的上半部分,中间部分得到侧边框,底部得到 - 好,底部部分)。 所以,如果我们只想要一个简单的样式,并且我们的单元格没有自定义的backgroundView(在90%的情况下就是这种情况),那么我们需要做的就是使用UITableViewStyleGrouped,并删除自定义背景。这可以通过以下两个步骤来完成:

将tableView样式更改为UITableViewStyleGrouped 在我们返回单元格之前,将以下行添加到cellForRow:

cell.backgroundView = [[[UIView alloc] initWithFrame:cell.bounds] autorelease];

就是这样。 tableView样式将与UITableViewStylePlain完全相同,但浮动标题除外。

希望这有帮助!

答案 12 :(得分:3)

适用于Swift 3 +

只需使用UITableViewStyleGrouped并使用以下内容将页脚高度设置为零:

override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
    return .leastNormalMagnitude
}

答案 13 :(得分:1)

另一种方法是在您想要标题开头之前创建一个空白部分,并将标题放在该部分上。由于该部分为空,标题将立即滚动。

答案 14 :(得分:1)

你可以在上面添加一个Section(零行),然后将上面的sectionFooterView设置为当前节的headerView,footerView不会浮动。 希望它能提供帮助。

答案 15 :(得分:1)

也许你可以在tableView上使用scrollViewDidScroll 并根据当前可见标题更改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)
   }
}

答案 16 :(得分:0)

要完全删除浮动部分标题部分,您可以执行以下操作:

- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    return [[UIView alloc] init];
}

return nil不起作用。

要禁用浮动但仍显示部分标题,您可以提供具有自己行为的自定义视图。

答案 17 :(得分:0)

**Swift 5.3 |以编程方式**

private func buildTableView() -> UITableView {
    let tableView = UITableView()
    tableView.translatesAutoresizingMaskIntoConstraints = false
    tableView.rowHeight = UITableView.automaticDimension
    tableView.showsVerticalScrollIndicator = false
    tableView.separatorStyle = .none
    let dummyViewHeight: CGFloat = 80
    tableView.tableFooterView = UIView(
        frame: CGRect(x: .zero,
                      y: .zero,
                      width: tableView.bounds.size.width,
                      height: dummyViewHeight))

    tableView.contentInset = UIEdgeInsets(top: .zero, left: .zero, bottom: -dummyViewHeight, right: .zero)
    return tableView
}

答案 18 :(得分:0)

一种棘手的方法是为标题添加一个空白部分。因为section没有单元格,所以它根本不会浮动。

答案 19 :(得分:0)

该代码段仅在第一部分显示粘性标题。其他节标题将带有单元格。

func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {

    if section == 1 {
        tableView.contentInset = .zero
    }

}

func tableView(_ tableView: UITableView, didEndDisplayingHeaderView view: UIView, forSection section: Int) {
    if section == 0 {
        tableView.contentInset = .init(top: -tableView.sectionHeaderHeight, left: 0, bottom: 0, right: 0)
    }
}

答案 20 :(得分:0)

@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 :(得分:0)

忽略XAK。如果您希望您的应用有机会被苹果接受,请不要探索任何私人方法。

如果您使用Interface Builder,这是最简单的。你可以在视图的顶部添加一个UIView(图像将在哪里),然后在下面添加你的tableview。 IB应相应调整大小;也就是说,tableview的顶部触及你刚刚添加的UIView的底部,它的高度覆盖了屏幕的其余部分。

这里的想法是,如果UIView实际上不是表视图的一部分,它将不会与tableview一起滚动。即忽略tableview标题。

如果你没有使用界面构建器,那就有点复杂了,因为你必须得到桌面视图的定位和高度正确。

答案 22 :(得分:0)

检查答案如何使用StoryBoard实现标题:Table Header Views in StoryBoards

另请注意,如果您未实施

viewForHeaderInSection:(NSInteger)section

它不会浮动,这正是你想要的。

答案 23 :(得分:-1)

也许你可以简单地使标题视图背景透明:

- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section {
    view.tintColor = [UIColor clearColor];
}

或全球应用:

    [UITableViewHeaderFooterView appearance].tintColor = [UIColor clearColor];

答案 24 :(得分:-1)

根据@ 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)

答案 25 :(得分:-1)

这可以通过在UITableViewController的viewDidLoad方法中手动分配标题视图而不是使用委托的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];
}

当用户滚动时,标题视图将消失。我不知道为什么会这样,但它似乎达到了你想要做的目的。

答案 26 :(得分:-2)

参考:https://stackoverflow.com/a/26306212

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
}

这有助于使用标题空间

答案 27 :(得分:-2)

我还有另一种更简单的解决方案,可以在没有自动布局的情况下使用,并通过XIB完成所有工作:

1 /将标题直接拖放到tableview上,将标题放在tableview中。

2 /在新制作的标题的大小检查器中,只需更改其自动调整大小:您应该只保留顶部,左侧和右侧锚点,以及水平填充。

That's how it should be set for the header

这应该可以做到!

答案 28 :(得分:-4)

您可以通过在tableview委托类中实现viewForHeaderInSection方法轻松实现此目的。这个方法需要一个UIView作为返回对象(这是你的标题视图)。我在我的代码中做了同样的事情

答案 29 :(得分:-4)

2020最新更新

使用Xcode 14测试。

要隐藏任何节标题,请返回nil作为节委托的标题

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return nil
}