【问题标题】:UITableView set to static cells. Is it possible to hide some of the cells programmatically?UITableView 设置为静态单元格。是否可以以编程方式隐藏某些单元格?
【发布时间】:2012-01-05 19:29:30
【问题描述】:

UITableView 设置为静态单元格。

是否可以通过编程方式隐藏某些单元格?

【问题讨论】:

    标签: ios objective-c uitableview


    【解决方案1】:

    在 UITable 中隐藏静态单元格:

    1. 添加此方法

    在你的 UITableView 控制器委托类中:

    目标-C:

    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        UITableViewCell* cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
    
        if(cell == self.cellYouWantToHide)
            return 0; //set the hidden cell's height to 0
    
        return [super tableView:tableView heightForRowAtIndexPath:indexPath];
    }
    

    斯威夫特:

    override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        var cell = super.tableView(tableView, cellForRowAtIndexPath: indexPath)
    
        if cell == self.cellYouWantToHide {
            return 0
        }
    
        return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
    }
    

    将为 UITable 中的每个单元格调用此方法。一旦它为您要隐藏的单元格调用它,我们将其高度设置为 0。我们通过为其创建一个出口来识别目标单元格:

    1. 在设计器中,为要隐藏的单元格创建一个出口。 一个这样的单元格的出口在上面称为“cellYouWantToHide”。
    2. 检查 IB 中的“剪辑子视图”以查找要隐藏的单元格。 您要隐藏的单元格需要具有 ClipToBounds = YES。否则文字会堆积在 UITableView 中。

    【讨论】:

    • 不错的解决方案。为避免ClipToBounds 问题,您还可以将单元格设置为隐藏。这对我来说似乎更干净。 ;-)
    • +1 表示 ClipToBounds = YES。其他线程中的许多解决方案都错过了这一点。
    • 好主意。这是我找到的最简单的解决方案。其他解决方案在两个或多个位置有代码。顺便说一句,在 IB 中,ClipToBounds 被列为“剪辑子视图”。
    • 稍作修正,使用 self.cellYouWantToHide 而不是 this.cellYouWantToHide。
    • 不创建单元格对象,我们也可以使用“index.row”隐藏“uitableviewcell”
    【解决方案2】:

    您正在寻找此解决方案:

    StaticDataTableViewController 2.0

    https://github.com/xelvenone/StaticDataTableViewController

    它可以显示/隐藏/重新加载任何带有或不带有动画的静态单元格!

    [self cell:self.outletToMyStaticCell1 setHidden:hide]; 
    [self cell:self.outletToMyStaticCell2 setHidden:hide]; 
    [self reloadDataAnimated:YES];
    

    注意始终只使用 (reloadDataAnimated:YES/NO) (不要直接调用[self.tableView reloadData])

    这不使用将高度设置为 0 的 hacky 解决方案,并允许您为更改设置动画并隐藏整个部分

    【讨论】:

    • 该解决方案的一个问题是它会在隐藏单元格所在的位置留下空隙。
    • 你的意思是差距?你能更好地描述一下情况吗,也许直接在github上?您是否运行了示例?
    • 我的意思是,如果您有例如三个部分,并且您从中间部分隐藏单元格,则该部分所在的空间仍然存在。我没有尝试示例项目,但我确实尝试了代码。我会试一试。
    • 查看示例,有一个更大的更新,也许你有一些旧代码......非常适合我
    • 我尝试了该示例,它似乎在那里工作,我唯一不同的是使用IBOutletCollection,但我不知道这会有什么不同。我昨天才下载了代码,所以我认为它不是旧版本。
    【解决方案3】:

    最好的方法是在下面的博客中描述 http://ali-reynolds.com/2013/06/29/hide-cells-in-static-table-view/

    在界面生成器中正常设计静态表格视图 – 完成所有可能隐藏的单元格。但有一件事你 必须对您要隐藏的每个潜在单元格执行 - 检查 单元格的“剪辑子视图”属性,否则为 当您尝试隐藏它时,单元格不会消失(通过缩小它 高度 - 稍后会更多)。

    所以 - 您在单元格中有一个开关,并且该开关应该隐藏 并显示一些静态单元格。将它连接到 IBAction 并在那里做 这个:

    [self.tableView beginUpdates];
    [self.tableView endUpdates];
    

    这为您提供了漂亮的单元格动画,并且 消失。现在实现以下表格视图委托方法:

    - (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
        if (indexPath.section == 1 && indexPath.row == 1) { // This is the cell to hide - change as you need
        // Show or hide cell
            if (self.mySwitch.on) {
                return 44; // Show the cell - adjust the height as you need
            } else {
                return 0; // Hide the cell
            }
       }
       return 44;
    }
    

    就是这样。拨动开关,单元格隐藏并重新出现 漂亮、流畅的动画。

    【讨论】:

    • 更新:您还需要将单元格标签设置为隐藏/显示单元格隐藏/显示,否则标签会乱七八糟。
    • 您应该注意,如果静态单元格内容中的任何 UIView 对 cell.content 有任何约束,如果这些约束对您的新单元格高度无效,您可能会收到运行时错误。
    • 我知道这个技巧适用于动态内容。也可以很好地与静态配合使用。也很简单。
    • 这确实有效,但要弥补一个缺失点:如果要隐藏/显示的行包含日期选择器,则只执行 [self.tableView beginUpdates]; [self.tableView endUpdates];隐藏时仍然会留下小故障。要消除故障,您应该调用 [self.tableView reloadRowsAtIndexPaths:@[indexPathOfTargetRow] withRowAnimation:UITableViewRowAnimationNone];还要注意行动画在这里以某种方式“禁用”。
    • 该博客链接现在是否已失效,并带有指向“狡猾”网站的链接,还是只有我?
    【解决方案4】:

    我的解决方案与 Gareth 的方向相似,但我做的一些事情不同。

    这里是:

    1.隐藏单元格

    没有办法直接隐藏单元格。 UITableViewController 是提供静态单元格的数据源,目前没有办法告诉它“不提供单元格 x”。 所以我们必须提供我们自己的数据源,它委托给UITableViewController 以获取静态单元格。

    最简单的方法是继承UITableViewController,并覆盖所有在隐藏单元格时需要表现不同的方法

    在最简单的情况下(单节表,所有单元格的高度相同),如下所示:

    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section    
    {
        return [super tableView:tableView numberOfRowsInSection:section] - numberOfCellsHidden;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        // Recalculate indexPath based on hidden cells
        indexPath = [self offsetIndexPath:indexPath];
    
        return [super tableView:tableView cellForRowAtIndexPath:indexPath];
    }
    
    - (NSIndexPath*)offsetIndexPath:(NSIndexPath*)indexPath
    {
        int offsetSection = indexPath.section; // Also offset section if you intend to hide whole sections
        int numberOfCellsHiddenAbove = ... // Calculate how many cells are hidden above the given indexPath.row
        int offsetRow = indexPath.row + numberOfCellsHiddenAbove;
    
        return [NSIndexPath indexPathForRow:offsetRow inSection:offsetSection];
    }
    

    如果您的表格有多个部分,或者单元格的高度不同,则需要覆盖更多方法。同样的原则也适用于此:在委托给 super 之前,您需要偏移 indexPath、section 和 row。

    还请记住,didSelectRowAtIndexPath: 等方法的 indexPath 参数对于同一单元格会有所不同,具体取决于状态(即隐藏单元格的数量)。因此,始终偏移任何 indexPath 参数并使用这些值可能是一个好主意。

    2。动画变化

    正如 Gareth 已经说过的,如果您使用 reloadSections:withRowAnimation: 方法为更改设置动画,则会出现重大故障。

    我发现,如果您之后立即致电reloadData:,动画效果会大大改善(只剩下小故障)。动画后表格正确显示。

    所以我正在做的是:

    - (void)changeState
    {
         // Change state so cells are hidden/unhidden
         ...
    
        // Reload all sections
        NSIndexSet* reloadSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [self numberOfSectionsInTableView:tableView])];
    
        [tableView reloadSections:reloadSet withRowAnimation:UITableViewRowAnimationAutomatic];
        [tableView reloadData];
    }
    

    【讨论】:

    • 您找到解决动画小故障的方法了吗?对我来说,单元格之间的分隔线不会正确设置动画,我宁愿不使用动画而不是使用动画。不过很好的解决方案!
    • 我的问题是静态单元格 numberOfRowsInSection: 仅在第一次加载表时才被调用。当我调用 [self.tableView reloadData] - numberOfRowsInSection: 永远不会再被调用。只有cellForRowAtIndexPath: 被调用。我错过了什么?
    【解决方案5】:
    1. 在设计器中,为要隐藏的单元格创建一个出口。例如你想隐藏'cellOne',所以在 viewDidLoad() 中这样做

    cellOneOutlet.hidden = true

    现在覆盖下面的方法,检查哪些单元格状态是隐藏的,并为这些单元格返回高度 0。这是您可以快速隐藏静态 tableView 中的任何单元格的多种方法之一。

    override func tableView(tableView: UITableView, heightForRowAtIndexPathindexPath: NSIndexPath) -> CGFloat 
    {
    
    let tableViewCell = super.tableView(tableView,cellForRowAtIndexPath: indexPath)
    
            if tableViewCell.hidden == true
            {
                return 0
            }
            else{
                 return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
            }
    
    }
    

    【讨论】:

    • 迄今为止最好的解决方案!
    • 修改后添加 tableView.reloadData() 就完美了。为我节省了很多精力来更改解决方案!谢谢
    • Swift 4 不允许我使用let tableViewCell = super.tableView(tableView,cellForRowAtIndexPath: indexPath)。我假设它被 let tableViewCell = tableView.cellForRow(at: indexPath as IndexPath) 取代。
    • 因为我在UITableViewController 上使用静态单元格,所以我没有任何UITableView 委托方法。为了让它调用heightForRow,我还需要其他方法吗?
    • @CliftonLabrum 不,您只能覆盖此方法。
    【解决方案6】:

    我想出了一个替代方案,它实际上隐藏了部分并且不删除它们。我尝试了@henning77 的方法,但是当我更改静态 UITableView 的部分数量时,我一直遇到问题。这种方法对我来说效果很好,但我主要是想隐藏部分而不是行。我成功地删除了一些行,但它更混乱,所以我试图将东西分组到我需要显示或隐藏的部分。这是我如何隐藏部分的示例:

    首先我声明一个 NSMutableArray 属性

    @property (nonatomic, strong) NSMutableArray *hiddenSections;
    

    在 viewDidLoad 中(或查询数据后),您可以将要隐藏的部分添加到数组中。

    - (void)viewDidLoad
    {
        hiddenSections = [NSMutableArray new];
    
        if(some piece of data is empty){
            // Add index of section that should be hidden
            [self.hiddenSections addObject:[NSNumber numberWithInt:1]];
        }
    
        ... add as many sections to the array as needed
    
        [self.tableView reloadData];
    }
    

    然后实现下面的TableView委托方法

    - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
    {
        if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
            return nil;
        }
    
        return [super tableView:tableView titleForHeaderInSection:section];
    }
    
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        if([self.hiddenSections containsObject:[NSNumber numberWithInt:indexPath.section]]){
            return 0;
        }
    
        return [super tableView:tableView heightForRowAtIndexPath:[self offsetIndexPath:indexPath]];
    }
    
    - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
    {
        if([self.hiddenSections containsObject:[NSNumber numberWithInt:indexPath.section]]){
            [cell setHidden:YES];
        }
    }
    

    然后将隐藏部分的页眉和页脚高度设置为 1,因为您不能将高度设置为 0。这会导致额外的 2 像素空间,但我们可以通过调整下一个可见页眉的高度来弥补.

    -(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section 
    {
        CGFloat height = [super tableView:tableView heightForHeaderInSection:section];
    
        if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
            height = 1; // Can't be zero
        }
        else if([self tableView:tableView titleForHeaderInSection:section] == nil){ // Only adjust if title is nil
            // Adjust height for previous hidden sections
            CGFloat adjust = 0;
    
            for(int i = (section - 1); i >= 0; i--){
                if([self.hiddenSections containsObject:[NSNumber numberWithInt:i]]){
                    adjust = adjust + 2;
                }
                else {
                    break;
                }
            }
    
            if(adjust > 0)
            {                
                if(height == -1){
                    height = self.tableView.sectionHeaderHeight;
                }
    
                height = height - adjust;
    
                if(height < 1){
                    height = 1;
                }
            }
        }
    
        return height;
    }
    
    -(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section 
    {   
        if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
            return 1;
        }
        return [super tableView:tableView heightForFooterInSection:section];
    }
    

    然后,如果您确实有要隐藏的特定行,您可以调整 numberOfRowsInSection 以及在 cellForRowAtIndexPath 中返回哪些行。在此示例中,我有一个包含三行的部分,其中任何三行都可能为空并需要删除。

    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        NSInteger rows = [super tableView:tableView numberOfRowsInSection:section];
    
        if(self.organization != nil){
            if(section == 5){ // Contact
                if([self.organization objectForKey:@"Phone"] == [NSNull null]){     
                    rows--;
                }
    
                if([self.organization objectForKey:@"Email"] == [NSNull null]){     
                    rows--;
                }
    
                if([self.organization objectForKey:@"City"] == [NSNull null]){     
                    rows--;
                }
            }
        }
    
        return rows;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {    
        return [super tableView:tableView cellForRowAtIndexPath:[self offsetIndexPath:indexPath]];
    }
    

    使用此 offsetIndexPath 计算您有条件地删除行的行的 indexPath。如果您只是隐藏部分,则不需要

    - (NSIndexPath *)offsetIndexPath:(NSIndexPath*)indexPath
    {
        int row = indexPath.row;
    
        if(self.organization != nil){
            if(indexPath.section == 5){
                // Adjust row to return based on which rows before are hidden
                if(indexPath.row == 0 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Email"] != [NSNull null]){     
                    row++;
                }
                else if(indexPath.row == 0 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Address"] != [NSNull null]){     
                    row = row + 2;
                }
                else if(indexPath.row == 1 && [self.organization objectForKey:@"Phone"] != [NSNull null] && [self.organization objectForKey:@"Email"] == [NSNull null]){     
                    row++;
                }
                else if(indexPath.row == 1 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Email"] != [NSNull null]){     
                    row++;
                }
            }
        }
    
        NSIndexPath *offsetPath = [NSIndexPath indexPathForRow:row inSection:indexPath.section];
    
        return offsetPath;
    }
    

    有很多方法可以覆盖,但我喜欢这种方法的地方在于它是可重用的。设置 hiddenSections 数组,添加到它,它将隐藏正确的部分。隐藏行有点棘手,但可能。如果我们使用分组的 UITableView,我们不能只将我们想要隐藏的行的高度设置为 0,因为边框不会被正确绘制。

    【讨论】:

    • 我可能会使用NSMutableSet 代替hiddenSections。由于您主要测试会员资格,因此速度要快得多。
    • 很好的答案,奥斯汀。我对这个答案投了赞成票,并将在未来将其用作我的项目的参考。 pixelfreak 还提出了一个很好的观点,即将 NSMutableSet 用于 hiddenSections,尽管我知道你的回答比你应该使用哪种类型的数据结构更具有概念性。
    【解决方案7】:

    事实证明,您可以在静态 UITableView 中隐藏和显示单元格 - 并带有动画。而且实现起来并不难。

    Demo project

    Demo project video

    要点:

    1. Use tableView:heightForRowAtIndexPath: 根据某些状态动态指定单元格高度。
    2. 当状态改变时,通过调用tableView.beginUpdates();tableView.endUpdates() 显示/隐藏动画单元格
    3. 不要在tableView:heightForRowAtIndexPath: 内调用tableView.cellForRowAtIndexPath:。使用缓存的 indexPaths 来区分单元格。
    4. 不要隐藏单元格。改为在 Xcode 中设置“剪辑子视图”属性。
    5. 使用自定义单元格(不是普通等)获得漂亮的隐藏动画。此外,在单元格高度 == 0 的情况下正确处理自动布局。

    More info in my blog (Russian language)

    【讨论】:

    • 这一点对我来说很重要:“不要隐藏单元格。改为在 Xcode 中设置“剪辑子视图”属性。”
    【解决方案8】:

    根据 Justas 的回答,但对于 Swift 4:

    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        let cell = super.tableView(tableView, cellForRowAt: indexPath)
    
        if cell == self.cellYouWantToHide {
            return 0
        }
    
        return super.tableView(tableView, heightForRowAt: indexPath)
    }
    

    【讨论】:

    • 如果在行已经可见的情况下更改高度,您可能需要tableView.reloadRows(at:, with:) 来更新单元格。
    【解决方案9】:

    是的,这绝对是可能的,尽管我目前正在努力解决同样的问题。我已经设法让细胞隐藏起来,一切正常,但我目前无法让这个东西整齐地动画。这是我发现的:

    我根据第一部分第一行中的 ON/OFF 开关的状态隐藏行。如果开关打开,则在同一部分中其下方有 1 行,否则有 2 行不同。

    我在切换开关时调用了一个选择器,我设置了一个变量来指示我处于哪种状态。然后我调用:

    [[self tableView] reloadData];
    

    我重写了 tableView:willDisplayCell:forRowAtIndexPath: 函数,如果单元格应该被隐藏,我这样做:

    [cell setHidden:YES];
    

    这会隐藏单元格及其内容,但不会删除它占用的空间。

    要删除空格,请覆盖 tableView:heightForRowAtIndexPath: 函数并为应该隐藏的行返回 0。

    您还需要覆盖 tableView:numberOfRowsInSection: 并返回该部分中的行数。您必须在这里做一些奇怪的事情,以便如果您的表格是分组样式,圆角会出现在正确的单元格上。在我的静态表中,该部分包含完整的单元格,因此第一个单元格包含选项,然后是 1 个单元格用于 ON 状态选项,另外 2 个单元格用于 OFF 状态选项,总共 4 个单元格。 When the option is ON, I have to return 4, this includes the hidden option so that the last option displayed has a rounded box. When the option is off, the last two options are not displayed so I return 2. This all feels clunky.抱歉,如果这不是很清楚,描述起来很棘手。只是为了说明设置,这是 IB 中表格部分的构造:

    • 第 0 行:带 ON/OFF 开关的选项
    • 第 1 行:选项打开时显示
    • 第 2 行:选项关闭时显示
    • 第 3 行:选项关闭时显示

    所以当该选项上时,表中报告两行:

    • 第 0 行:带 ON/OFF 开关的选项
    • 第 1 行:选项打开时显示

    When the option is OFF the table reports four rows which are:

    • 第 0 行:带 ON/OFF 开关的选项
    • 第 1 行:选项打开时显示
    • 第 2 行:选项关闭时显示
    • 第 3 行:选项关闭时显示

    由于几个原因,这种方法感觉不正确,就我到目前为止的实验而言,如果你找到更好的方法,请告诉我。到目前为止我观察到的问题是:

    • 告诉表行数与可能包含在基础数据中的行数不同感觉是错误的。

    • 我似乎无法为更改设置动画。我尝试使用 tableView:reloadSections:withRowAnimation: 而不是 reloadData 并且结果似乎没有意义,我仍在尝试使其正常工作。目前似乎发生的情况是 tableView 没有更新正确的行,因此应该显示的行保持隐藏状态,并且在第一行下方留下空白。我认为这可能与关于基础数据的第一点有关。

    希望有人能够提出替代方法或如何使用动画进行扩展,但也许这会让你开始。我很抱歉缺少函数的超链接,我把它们放进去,但它们被垃圾邮件过滤器拒绝了,因为我是一个相当新的用户。

    【讨论】:

    • 我很确定您应该在隐藏单元格后再致电[[self tableView] reloadData];
    • 很抱歉恢复这个,但是你怎么能继承 UITableViewController 并将它与静态单元格一起使用呢? Xcode 不允许我这样做。
    • Nessup,你不需要继承 UITableView。在情节提要中选择您的 TableViewController,然后单击 TableView。现在您可以在动态/静态单元格之间进行选择。
    • 我找到了如何为静态单元格设置动画隐藏/显示的解决方案。只需在 UITableViewController 子类中调用 return [super tableView:tableView cellForRowAtIndexPath:indexPath]; 即可创建静态单元格。索引路径是静态索引的 - 不是动态的......
    【解决方案10】:

    好的,经过一番尝试,我有一个不常见的答案。 我正在使用“isHidden”或“hidden”变量来检查是否应该隐藏此单元格。

    1. 为您的视图控制器创建一个 IBOutlet。 @IBOutlet weak var myCell: UITableViewCell!

    2. 在你的自定义函数中更新myCell,例如你可以在viewDidLoad中添加它:

    override func viewDidLoad() { super.viewDidLoad() self.myCell.isHidden = true }

    1. 在您的委托方法中:

    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { let cell = super.tableView(tableView, cellForRowAt: indexPath) guard !cell.isHidden else { return 0 } return super.tableView(tableView, heightForRowAt: indexPath) }

    这会减少你在委托方法中的逻辑,你只需要专注于你的业务需求。

    【讨论】:

      【解决方案11】:

      简单的 iOS 11 & IB/Storyboard 兼容方法

      对于 iOS 11,我发现 Mohamed Saleh's answer 的修改版本效果最好,并根据 Apple 的文档进行了一些改进。它的动画效果很好,避免了任何丑陋的 hack 或硬编码值,并且使用已在 Interface Builder 中设置的行高

      基本概念是将任何隐藏行的行高设置为 0。然后使用tableView.performBatchUpdates 触发一个始终如一的动画。

      设置单元格高度

      override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
          if indexPath == indexPathOfHiddenCell {
              if cellIsHidden {
                  return 0
              }
          }
          // Calling super will use the height set in your storyboard, avoiding hardcoded values
          return super.tableView(tableView, heightForRowAt: indexPath)
      }
      

      您需要确保 cellIsHiddenindexPathOfHiddenCell 已根据您的用例进行适当设置。对于我的代码,它们是我的表视图控制器上的属性。

      切换单元格

      在任何控制可见性的方法中(可能是按钮操作或didSelectRow),在performBatchUpdates 块内切换cellIsHidden 状态:

      tableView.performBatchUpdates({
                      // Use self to capture for block
                      self.cellIsHidden = !self.cellIsHidden 
                  }, completion: nil)
      

      Apple recommends performBatchUpdates over beginUpdates/endUpdates 尽可能。

      【讨论】:

        【解决方案12】:

        由于自动布局问题,上述隐藏/显示单元格、更改 rowHeight 或混淆自动布局约束的答案对我不起作用。代码变得无法忍受。

        对于一个简单的静态表,最适合我的是:

        1. 为静态表中的每个单元格创建一个插座
        2. 创建一个数组,只显示单元格的出口
        3. 覆盖 cellForRowAtIndexPath 以返回数组中的单元格
        4. 覆盖 numberOfRowsInSection 以返回数组的计数
        5. 实现一种方法来确定该数组中需要包含哪些单元格,并在需要时调用该方法,然后重新加载数据。

        这是我的表格视图控制器的一个示例:

        @IBOutlet weak var titleCell: UITableViewCell!
        @IBOutlet weak var nagCell: UITableViewCell!
        @IBOutlet weak var categoryCell: UITableViewCell!
        
        var cellsToShow: [UITableViewCell] = []
        
        override func viewDidLoad() {
            super.viewDidLoad()
            determinCellsToShow()
        }
        
        func determinCellsToShow() {
            if detail!.duration.type != nil {
                cellsToShow = [titleCell, nagCell, categoryCell]
            }
            else {
                cellsToShow = [titleCell,  categoryCell]
            }
        }
        
        override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
            return cellsToShow[indexPath.row]
        }
        
        override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return cellsToShow.count
        }
        

        【讨论】:

        • 2020,这是最好的解决方案。无需破解。
        • 将单元格高度设置为零会对我造成大量约束警告,这是无法修复的。这个策略对我有用,但我有多个部分,需要隐藏一个部分。隐藏部分必须存在,但它没有标题标题和单元格,因此它不占用可见空间。我有一个 Section 类型,它有一个单元格数组。还有一组Sections。然后覆盖 numberOfSectionsnumberOfRowsInSectioncellForRowAtIndexPath,以及部分标题。
        【解决方案13】:

        我找到了在静态表格中隐藏单元格的动画解决方案。

        // Class for wrapping Objective-C block
        typedef BOOL (^HidableCellVisibilityFunctor)();
        @interface BlockExecutor : NSObject
        @property (strong,nonatomic) HidableCellVisibilityFunctor block;
        + (BlockExecutor*)executorWithBlock:(HidableCellVisibilityFunctor)block;
        @end
        @implementation BlockExecutor
        @synthesize block = _block;
        + (BlockExecutor*)executorWithBlock:(HidableCellVisibilityFunctor)block
        {
            BlockExecutor * executor = [[BlockExecutor alloc] init];
            executor.block = block;
            return executor;
        }
        @end
        

        只需要一本额外的字典:

        @interface MyTableViewController ()
        @property (nonatomic) NSMutableDictionary * hidableCellsDict;
        @property (weak, nonatomic) IBOutlet UISwitch * birthdaySwitch;
        @end
        

        然后看看 MyTableViewController 的实现。我们需要两种方法来在可见索引和不可见索引之间转换 indexPath...

        - (NSIndexPath*)recoverIndexPath:(NSIndexPath *)indexPath
        {
            int rowDelta = 0;
            for (NSIndexPath * ip in [[self.hidableCellsDict allKeys] sortedArrayUsingSelector:@selector(compare:)])
            {
                BlockExecutor * executor = [self.hidableCellsDict objectForKey:ip];
                if (ip.section == indexPath.section
                    && ip.row <= indexPath.row + rowDelta
                    && !executor.block())
                {
                    rowDelta++;
                }
            }
            return [NSIndexPath indexPathForRow:indexPath.row+rowDelta inSection:indexPath.section];
        }
        
        - (NSIndexPath*)mapToNewIndexPath:(NSIndexPath *)indexPath
        {
            int rowDelta = 0;
            for (NSIndexPath * ip in [[self.hidableCellsDict allKeys] sortedArrayUsingSelector:@selector(compare:)])
            {
                BlockExecutor * executor = [self.hidableCellsDict objectForKey:ip];
                if (ip.section == indexPath.section
                    && ip.row < indexPath.row - rowDelta
                    && !executor.block())
                {
                    rowDelta++;
                }
            }
            return [NSIndexPath indexPathForRow:indexPath.row-rowDelta inSection:indexPath.section];
        }
        

        UISwitch 值更改的一个 IBAction:

        - (IBAction)birthdaySwitchChanged:(id)sender
        {
            NSIndexPath * indexPath = [self mapToNewIndexPath:[NSIndexPath indexPathForRow:1 inSection:1]];
            if (self.birthdaySwitch.on)
                [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            else
                [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
        }
        

        一些 UITableViewDataSource 和 UITableViewDelegate 方法:

        - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
        {
            int numberOfRows = [super tableView:tableView numberOfRowsInSection:section];
            for (NSIndexPath * indexPath in [self.hidableCellsDict allKeys])
                if (indexPath.section == section)
                {
                    BlockExecutor * executor = [self.hidableCellsDict objectForKey:indexPath];
                    numberOfRows -= (executor.block()?0:1);
                }
            return numberOfRows;
        }
        
        - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
        {
            indexPath = [self recoverIndexPath:indexPath];
            return [super tableView:tableView cellForRowAtIndexPath:indexPath];
        }
        
        - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
        {
            indexPath = [self recoverIndexPath:indexPath];
            return [super tableView:tableView heightForRowAtIndexPath:indexPath];
        }
        
        - (void)viewDidLoad
        {
            [super viewDidLoad];
        
            // initializing dictionary
            self.hidableCellsDict = [NSMutableDictionary dictionary];
            [self.hidableCellsDict setObject:[BlockExecutor executorWithBlock:^(){return self.birthdaySwitch.on;}] forKey:[NSIndexPath indexPathForRow:1 inSection:1]];
        }
        
        - (void)viewDidUnload
        {
            [self setBirthdaySwitch:nil];
            [super viewDidUnload];
        }
        
        @end
        

        【讨论】:

          【解决方案14】:

          swift回答:

          在您的 TableViewController 中添加以下方法:

          override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
              return indexPathOfCellYouWantToHide == indexPath ? 0 : super.tableView(tableView, heightForRowAtIndexPath: indexPath)
          }
          

          如果 tableView 尝试绘制您希望隐藏的单元格,则它不会显示它,因为由于上述方法,它的高度将设置为 0pt,其他一切都保持不变。

          请注意indexPathOfCellYouWantToHide可以随时更改:)

          【讨论】:

            【解决方案15】:

            在 > Swift 2.2 中,我在这里合并了几个答案。

            从情节提要中创建一个出口以链接到您的 staticCell。

            @IBOutlet weak var updateStaticCell: UITableViewCell!
            
            override func viewDidLoad() {
                ...
                updateStaticCell.hidden = true
            }
            
            override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
                if indexPath.row == 0 {
                    return 0
                } else {
                    return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
                }
            }
            

            我想隐藏我的第一个单元格,因此如上所述将高度设置为 0。

            【讨论】:

              【解决方案16】:

              斯威夫特 4:

              override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
                  var height = super.tableView(tableView, heightForRowAt: indexPath)
                  if (indexPath.row == HIDDENROW) {
                      height = 0.0
                  }
                  return height
              }
              

              【讨论】:

                【解决方案17】:

                对于在表格视图最底部隐藏单元格的最简单情况,您可以在隐藏单元格后调整 tableView 的 contentInset:

                - (void)adjustBottomInsetForHiddenSections:(NSInteger)numberOfHiddenSections
                {
                    CGFloat bottomInset = numberOfHiddenSections * 44.0; // or any other 'magic number
                    self.tableView.contentInset = UIEdgeInsetsMake(self.tableView.contentInset.top, self.tableView.contentInset.left, -bottomInset, self.tableView.contentInset.right);
                }
                

                【讨论】:

                  【解决方案18】:

                  这是使用https://github.com/k06a/ABStaticTableViewController 的新方法

                  NSIndexPath *ip = [NSIndexPath indexPathForRow:1 section:1];
                  [self deleteRowsAtIndexPaths:@[ip] withRowAnimation:UITableViewRowAnimationFade]
                  

                  【讨论】:

                    【解决方案19】:

                    来自 k06a (https://github.com/k06a/ABStaticTableViewController) 的解决方案更好,因为它隐藏了包括单元格页眉和页脚在内的整个部分,而此解决方案 (https://github.com/peterpaulis/StaticDataTableViewController) 隐藏了除页脚之外的所有内容。

                    编辑

                    如果您想在StaticDataTableViewController 中隐藏页脚,我刚刚找到了解决方案。这是您需要在 StaticTableViewController.m 文件中复制的内容:

                    - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
                        if ([tableView.dataSource tableView:tableView numberOfRowsInSection:section] == 0) {
                            return nil;
                        } else {
                            return [super tableView:tableView titleForFooterInSection:section];
                        }
                    }
                    
                    - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
                    
                        CGFloat height = [super tableView:tableView heightForFooterInSection:section];
                    
                        if (self.originalTable == nil) {
                            return height;
                        }
                    
                        if (!self.hideSectionsWithHiddenRows) {
                            return height;
                        }
                    
                        OriginalSection * os = self.originalTable.sections[section];
                        if ([os numberOfVissibleRows] == 0) {
                           //return 0;
                            return CGFLOAT_MIN;
                        } else {
                            return height;
                        }
                    
                        //return 0;
                        return CGFLOAT_MIN;
                    }
                    

                    【讨论】:

                      【解决方案20】:

                      当然可以。首先,返回您要显示的 tableView 单元格数量,然后调用 super 从情节提要中获取某个单元格并将其返回给 tableView:

                      override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
                          return self.mode.numberOfCells()
                      }
                      
                      override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
                          let cell = super.tableView(tableView, cellForRowAtIndexPath: self.mode.indexPathForIndexPath(indexPath))
                      
                          return cell
                      }
                      

                      如果你的单元格有不同的高度,也返回它:

                      override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
                          return super.tableView(tableView, heightForRowAtIndexPath: self.mode.indexPathForIndexPath(indexPath))
                      }
                      

                      【讨论】:

                        【解决方案21】:

                        除了@Saleh Masum 解决方案:

                        如果您遇到自动布局错误,您可以从tableViewCell.contentView中删除约束

                        斯威夫特 3:

                        override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
                            let tableViewCell = super.tableView(tableView, cellForRowAt: indexPath)
                        
                            if tableViewCell.isHidden == true
                            {
                                tableViewCell.contentView.removeConstraints(tableViewCell.contentView.constraints)
                                return 0
                            }
                            else{
                                return super.tableView(tableView, heightForRowAt: indexPath)
                            }
                        
                        }
                        

                        解决方案取决于您应用的流程。如果您想在同一个视图控制器实例中显示/隐藏单元格,这可能不是最佳选择,因为它移除了约束

                        【讨论】:

                          【解决方案22】:

                          我找到了一种更好的方法来动态隐藏静态单元格甚至部分,而无需任何黑客攻击。

                          将行高设置为 0 可以隐藏一行,但如果你想隐藏整个部分,即使你隐藏所有行也会保留一些空格,这不起作用。

                          我的方法是构建一个静态单元格的部分数组。然后表格视图的内容将由节数组驱动。

                          这里是一些示例代码:

                          var tableSections = [[UITableViewCell]]()
                          
                          private func configTableSections() {
                              // seciton A
                              tableSections.append([self.cell1InSectionA, self.cell2InSectionA])
                          
                              // section B
                              if shouldShowSectionB {
                                  tableSections.append([self.cell1InSectionB, self.cell2InSectionB])
                              }
                          
                              // section C
                              if shouldShowCell1InSectionC {
                                  tableSections.append([self.cell1InSectionC, self.cell2InSectionC, self.cell3InSectionC])
                              } else {
                                  tableSections.append([self.cell2InSectionC, self.cell3InSectionC])
                              }
                          }
                          
                          func numberOfSections(in tableView: UITableView) -> Int {
                              return tableSections.count
                          }
                          
                          func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
                              return tableSections[section].count
                          }
                          
                          func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
                              return tableSections[indexPath.section][indexPath.row]
                          }
                          

                          这样,您可以将所有配置代码放在一起,而无需编写讨厌的代码来计算行数和节数。当然,不再有0 高度。

                          这段代码也很容易维护。例如,如果您想添加/删除更多单元格或部分。

                          同样,您可以创建节头标题数组和节脚标题数组来动态配置节标题。

                          【讨论】:

                            猜你喜欢
                            • 2012-06-26
                            • 1970-01-01
                            • 2012-06-26
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            相关资源
                            最近更新 更多