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

Tri*_*cky 160 iphone cocoa-touch objective-c uikit ios

我正在使用a UITableView来布局内容'pages'.我正在使用表格视图的标题来布局某些图像等.如果它们没有浮动但我保持静态,但是当样式设置为时它们保持静态UITableViewStyleGrouped.

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

非常感谢,

sam*_*tte 318

一种可能更容易实现此目的的方法:

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);
Run Code Online (Sandbox Code Playgroud)

迅速:

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)
Run Code Online (Sandbox Code Playgroud)

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

  • 我看到的唯一缺点是顶部标题将不再显示(您只能通过向上滚动查看它).至少对我而言,它没有显示出来 (12认同)
  • 这个friggin就像一个魅力!! 表标题视图标题的存在会阻止节标题浮动.并且一个带有适当内容插入表的隐形标题可以解决这个问题.非常感谢你!想知道为什么这个答案没有引起太多关注 (5认同)
  • 您仍然可以通过增加顶部的高度,通过等于节标题高度的数字来显示表格的tableHeader视图,并将内容插入减少相同的数字. (5认同)
  • 仍然不相信!没有私有API,没有挖掘课程,没有!我已经多年来一直面临这个问题,并且已经在滚动视图的顶部添加了tableview(禁用了tableview滚动),这将使表头正常滚动.但是刚开始搜索苹果最近是否提供了任何新的方法来解决这个问题..很高兴我偶然发现了你的答案.再次感谢 (4认同)
  • 我希望我能再次投票,我相当确定这至少是我第三次结束这个问题,这解决了我的问题. (2认同)
  • 我发现这个解决方案超级hacky。如果您的标头大小不同(例如支持动态类型时),则效果不佳。 (2认同)

dav*_*d72 222

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

let tableView = UITableView(frame: .zero, style: .grouped)
Run Code Online (Sandbox Code Playgroud)

  • 在实施最受欢迎的一个之前,我学会了检查所有答案的好事:) (20认同)
  • "然后使用UITableViewStyleGrouped,有没有办法做到这一点?" (4认同)
  • 这正是我所寻找的.谢谢! (3认同)
  • 现在这些家伙,就是你要找的答案。请注意,您也可以在 AttributesInspector 中找到“TableView Style”属性。 (2认同)
  • 问题特别提到寻找"其他然后使用UITableViewStyleGrouped"的方式 (2认同)

小智 72

警告:此解决方案实现了保留的API方法.这可能会阻止Apple批准App在AppStore上分发.

我已经描述了在我的博客中浮动部分标题的私有方法

基本上,您只需要子类化UITableView并返回NO其两个方法:

- (BOOL)allowsHeaderViewsToFloat;
- (BOOL)allowsFooterViewsToFloat;
Run Code Online (Sandbox Code Playgroud)

  • 答案不值得推崇,因为它引用了私有API(并非每个人都在编写要提交给AppStore的代码).当答案恰好是正确的时候,这是双重的.为这些方法返回NO的子类化(或者更容易制作UITableView类别)会阻止标题浮动.如果您希望将其添加为公共API,请提交错误报告:http://bugreport.apple.com (37认同)
  • @jemmons"不是每个人都在编写要提交给AppStore的代码"Appstore并不是真正的问题.问题是苹果可以在不通信或弃用的情况下更改私有API,这会破坏您的应用.这就是为什么你不应该使用私有API而不是被Apple拒绝的更好的理由 (11认同)
  • 如果我们在App中实现该功能,Apple会如何意识到您正在使用私有API?据他们所知,我刚刚在UITableView的子类中实现了一个方法,他们甚至在没有解组代码的情况下甚至看不到它,并且它不会那么容易.它不是在私有API中调用方法,它只是实现一个.... (4认同)
  • @jemmons如果你不想让我对你的答案进行downvote,请将其标记为"此处使用私有API".免责声明:) (3认同)
  • 您的"我的博客"链接已损坏 (2认同)

Sum*_*war 29

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

正如在少数答案中所建议的那样,我能够实现的唯一可行解决方案是在表格视图中插入普通单元格并将它们作为截面标题处理,但实现它的更好方法是将这些单元格插入每个部分的第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;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 像往常一样实现titleForHeaderInSection(您可以使用自己的逻辑获取此值,但我更喜欢使用标准委托).

    - (NSString *)tableView: (UITableView *)tableView titleForHeaderInSection:(NSInteger)section
    {
        NSString *headerTitle = [sectionArray objectAtIndex:section];
        return headerTitle;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 像往常一样实现numberOfSectionsInTableView

    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
    {
        int sectionCount = [sectionArray count];
        return sectionCount;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  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
    }
    
    Run Code Online (Sandbox Code Playgroud)
  5. 在heightForHeaderInSection中返回0.0f.

    - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
    {
        return 0.0f;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  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
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  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;
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  9. 现在实现willSelectRowAtIndexPath并返回nil,如果indexpath.row == 0.这将关心didSelectRowAtIndexPath永远不会被截面标题行触发.

    - (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
        if (indexPath.row == 0)
        {
            return nil;
        }
    
        return indexPath;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  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
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

有了这个,你就完成了.您现在拥有一个完美滚动的非浮动节标题.


fra*_*yer 28

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

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

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

  • 是的......虽然看起来有点像黑客.这似乎是Apple的疏忽,因为显然代码就是这样做的,我们只需要能够设置一个标志. (11认同)
  • 当真?这得到了正确的答案? (6认同)
  • 检查下面的答案是否有正确的方法来实现效果,没有任何特殊的黑客攻击,只需将每个部分的第一个单元格作为其标题管理! (2认同)

Han*_*ney 25

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

问题表视图

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

简单


ada*_*ton 17

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

该样式作为backgroundView添加到单元格中,作为一个名为UIGroupTableViewCellBackground的类,它根据该部分中单元格的位置处理绘制不同的背景.

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

cell.backgroundView = [[[UIView alloc] initWithFrame:cell.bounds] autorelease];
Run Code Online (Sandbox Code Playgroud)

  • 不会将单元格的contentView转移到右边吗? (2认同)

Aks*_*Aks 14

更改TableView样式:

self.tableview = [[UITableView alloc] initwithFrame:frame style:UITableViewStyleGrouped];
Run Code Online (Sandbox Code Playgroud)

根据UITableView的苹果文档:

UITableViewStylePlain-普通表视图.任何节页眉或页脚都显示为内联分隔符,并在滚动表视图时浮动.

UITableViewStyleGrouped-一个表视图,其截面显示不同的行组.节标题和页脚不会浮动.

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

  • ☝️ 这应该标记为正确答案。另外,对于故事板爱好者,当您选择 UITableView 时,您可以在故事板属性检查器中拥有此属性 (2认同)

Mic*_*kiy 5

获得所需内容的最简单方法是将表格样式设置为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];
}
Run Code Online (Sandbox Code Playgroud)

不要尝试返回页脚视图,因为nil在你必须得到你想要的之后不要忘记设置标题高度和标题视图.


小智 5

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

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return sectionCount * 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (section%2 == 0) {
        return 0;
    }
    return _rowCount;
}
Run Code Online (Sandbox Code Playgroud)

那么需要做的是实现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;
}
Run Code Online (Sandbox Code Playgroud)

这种方法对您的数据源也几乎没有影响:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    int real_section = (int)indexPath.section / 2;
    //your code
}
Run Code Online (Sandbox Code Playgroud)

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


Tam*_*gel 5

对于斯威夫特 3+

只需使用UITableViewStyleGrouped以下命令并将页脚的高度设置为零:

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