更改 UITableView 节头的默认滚动行为

我有一个包含两个部分的 UITableView。这是一个简单的表视图。我使用 viewForHeaderInSection 为这些头创建自定义视图。目前为止,一切顺利。

默认的滚动行为是,当遇到某个部分时,该部分的标题会固定在导航栏下方,直到下一个部分滚动到视图中。

我的问题是: 我可以改变默认的行为,使节标题不停留在顶部锚定,而是,滚动下的导航栏与其余的节行?

我漏掉了什么明显的东西吗?

谢谢。

94138 次浏览

如果是我这样做的话,我会利用这样一个事实: 平原样式的 UITableView 有粘贴的标题,而分组样式的没有。我可能至少会尝试使用一个自定义的表单元格来模拟“分组”表中“普通”单元格的外观。

我还没有真正尝试过,所以它可能不会工作,但这就是我建议做的事情。

我将表添加到一个滚动视图中,这看起来效果不错。

为 tableView 分配一个负的插入。如果你有22px 高的部分标题,并且你不希望它们粘在一起,在你重新加载之后立即添加:

self.tableView.contentInset = UIEdgeInsetsMake(-22, 0, 0, 0);
self.tableView.contentSize = CGSizeMake(self.tableView.contentSize.width, self.tableView.contentSize.height+22);

对我来说很有效。也适用于部分页脚,只要在底部设置负插入即可。

我解决这个问题的方法是根据 UITableViewControllerDelegate(扩展 UIScrollViewDelegate)中的 contentInset调整 contentOffset,如下所示:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat sectionHeaderHeight = 40;
if (scrollView.contentOffset.y<=sectionHeaderHeight&&scrollView.contentOffset.y>=0) {
scrollView.contentInset = UIEdgeInsetsMake(-scrollView.contentOffset.y, 0, 0, 0);
} else if (scrollView.contentOffset.y>=sectionHeaderHeight) {
scrollView.contentInset = UIEdgeInsetsMake(-sectionHeaderHeight, 0, 0, 0);
}
}

唯一的问题是,当滚动到顶部时,它会失去一点弹性。


{注意: “40”应该是您的第0部分标题的精确高度。如果你使用的数字大于你的第0部分标题高度,你会看到手指的感觉受到影响(尝试像“1000”,你会看到弹跳行为有点怪异的顶部)。如果数字匹配您的第0部分标题高度,手指感觉似乎是完美或接近完美。}

您还可以添加一个顶部没有行的部分,只需使用前一个部分的页脚作为下一个部分的标题。

有几件事情需要做,以解决这个问题在一个非骇客的方式:

  1. 将表视图样式设置为 UITableViewStyleGrouped
  2. 将表视图 backgroundColor设置为 [UIColor clearColor]
  3. 使用 backgroundColor [UIColor clearColor]将每个表视图单元格上的 backgroundView设置为空视图
  4. 如果需要,可以适当地设置表视图 rowHeight,或者如果各个行的高度不同,则重写 tableView:heightForRowAtIndexPath:

使用一个透明视图设置表的 headerView,该视图与节视图中的标题高度相同。还可以在高处使用 y 帧来初始化桌面视图。

self.tableview = [[UITableView alloc] initWithFrame:CGRectMake(0, - height, 300, 400)];


UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, width, height)] autorelease];
[self.tableView setTableHeaderView:headerView];

我知道它来得很晚,但我已经找到了最终的解决办法!

如果有10个部分,那么要做的是让 dataSource 返回20。对节头使用偶数,对节内容使用奇数。就像这样

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section%2 == 0) {
return 0;
}else {
return 5;
}
}


-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if (section%2 == 0) {
return [NSString stringWithFormat:@"%i", section+1];
}else {
return nil;
}
}

好了 D

我了解到,只需设置 tableHeaderView 属性就可以实现这一点,例如:

 tableView.tableHeaderView = customView;

就是这样。

我找到了一个替代的解决方案,使用每个部分的第一个单元格而不是一个真正的头部单元格,这个解决方案看起来不那么干净,但是工作得很好,你可以使用一个定义的原型单元格作为你的头部单元格,在方法 CellForRowAtIndexPath中请求 indexPath.row = = 0,如果正确,使用头部单元格原型单元格,否则使用你的默认原型单元格。

检查我的答案 给你。这是实现非浮动部分标题最简单的方法 没有任何黑客攻击。

最初发布的 给你,一个快速解决方案使用 IB。同样可以通过编程完成,虽然非常简单。

一个可能更简单的实现方法(使用 IB) :

将 UIView 拖动到 TableView 上,使其成为其标题视图。

  1. 将页眉视图高度设置为100px
  2. 将 tableview contentInset (top)设置为 -100
  3. 节标题现在将像任何常规单元格一样滚动。

一些人评论说这个解决方案隐藏了第一个头,但是我没有注意到任何这样的问题。这个方法对我来说非常有效,是目前为止我所见过的最简单的解决方案。

到目前为止,我对这里描述的解决方案并不满意,所以我尝试将它们结合起来。结果是以下代码,灵感来自@awulf 和@cescofried。它适合我,因为我没有真正的表视图头。如果已经有了表视图标头,则可能需要调整高度。

// Set the edge inset
self.tableView.contentInset = UIEdgeInsetsMake(-23.0f, 0, 0, 0);


// Add a transparent UIView with the height of the section header (ARC enabled)
[self.tableView setTableHeaderView:[[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 23.0f)]];

@ LocoMike 的回答最适合我的 tableView,不过在使用页脚时它也坏了。 因此,在使用页眉和页脚时,这是更正后的解决方案:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return (self.sections.count + 1) * 3;
}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section % 3 != 1) {
return 0;
}
section = section / 3;
...
}


- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if (section % 3 != 0) {
return nil;
}
section = section / 3;
...
}


- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
if (section % 3 != 0) {
return 0;
}
section = section / 3;
...
}


- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
if (section % 3 != 2) {
return 0;
}
section = section / 3;
...
}


- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
if (section % 3 != 0) {
return nil;
}
section = section / 3;
...
}


- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
if (section % 3 != 2) {
return nil;
}
section = section / 3;
...
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
int section = indexPath.section;
section = section / 3;
...
}

现在分组样式看起来基本上和 iOS7中的普通样式一样(在平面和背景方面) ,对我们来说,最好和最简单的(也就是最不粗糙的)修复方法就是简单地将表格视图的样式改为分组。当我们在顶部集成一个滚动式导航栏时,使用 contentInsets 进行顶部访问总是一个问题。使用分组表视图样式,它看起来完全相同(与我们的单元格一样) ,并且节标题保持不变。没有滚动奇怪。

只需更改 TableView 样式:

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

UITableViewStyle 文档 :

UITableViewStylePlain- 一个普通的表格视图。在滚动表视图时,任何区段标题或页脚都显示为内联分隔符和 float。

UITableViewStyleGrouped- 一种表格视图,其节呈现不同的行组。节头和节尾不浮动。

更改 TableView 样式:

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

根据 UITableView 的苹果文档:

UITableViewStylePlain- 一个普通的表格视图 页脚显示为内联分隔符,当表 视图滚动。

UITableViewStyleGroupe-一个表格视图,其中的部分显示不同的 行组。部分标题和页脚不浮动。希望 这个小小的改变会帮助你. 。

快速版@awulf 的答案,这很棒!

func scrollViewDidScroll(scrollView: UIScrollView) {
let sectionHeight: CGFloat = 80
if scrollView.contentOffset.y <= sectionHeight {
scrollView.contentInset = UIEdgeInsetsMake( -scrollView.contentOffset.y, 0, 0, 0)
}else if scrollView.contentOffset.y >= sectionHeight {
scrollView.contentInset = UIEdgeInsetsMake(-sectionHeight, 0, 0, 0)
}
}

Select Grouped TableView style

在故事板中从 tableView 的属性检查器中选择 GroupedTableView 样式。