UITableView设置为静态单元格。是否可以以编程方式隐藏某些单元格?


Answers:


48

您正在寻找此解决方案:

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解决方案,而是可以为更改设置动画并隐藏整个部分


6
该解决方案的一个问题是,它在隐藏单元所在的位置留下了空白。
杰克

你是怎么说差距的?您能否更好地描述这种情况,也许直接在github上?您是否运行了样本?
彼得·拉皮苏

1
我的意思是,例如,如果您有三个部分,并且从中间部分隐藏了单元格,则保留该部分所在的空间。我没有尝试示例项目,但是我尝试了代码。我将尝试示例。
2013年

1
查看示例,有一个较大的更新,也许您有一些旧代码...对我来说很完美
Peter Lapisu

我尝试了该示例,并且似乎可以在其中工作,我唯一不同的是使用a,IBOutletCollection但我不知道这样做会有什么不同。我昨天才下载代码,所以我认为它不是旧版本。
2013年

164

要在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中。

10
不错的解决方案。为避免此ClipToBounds问题,您还可以将单元格设置为隐藏。在我看来,这看起来更干净。;-)
MonsieurDart 2014年

13
ClipToBounds的+1 =是。其他线程中的Numeorus解决方案没有做到这一点。
杰夫

2
好想法。这是我找到的最简单的解决方案。其他解决方案在两个或多个位置具有代码。顺便说一句,在IB中,ClipToBounds被列为“剪辑子视图”。
VaporwareWolf 2014年

1
稍作修正,使用self .cellYouWantToHide代替 .cellYouWantToHide。
Zoltan Vinkler 2015年

2
在不创建单元格对象的情况下,我们也可以使用“ index.row”隐藏“ uitableviewcell”
g212gs 16-10-26

38

最佳方法如以下博客中所述 :http://ali-reynolds.com/2013/06/29/hide-cells-in-static-table-view/

在界面生成器中按常规设计静态表视图–包含所有可能隐藏的单元格。但是,对于要隐藏的每个潜在单元格,您必须做一件事–检查该单元格的“ Clip subviews”属性,否则当您尝试隐藏它时,该单元格的内容不会消失(缩小高度) –稍后)。

这样-您在一个单元格中有一个开关,并且该开关应该隐藏并显示一些静态单元格。将其连接到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;
}

就是这样。按下开关,单元格将隐藏起来并以流畅的动画重新出现。


更新:您还需要将“单元格标签”设置为“隐藏/显示”,否则标签会混乱。
Mohamed Saleh 2013年

1
您应该注意,如果静态单元格内容中的任何UIView对cell.content有任何约束,那么如果这些约束对于您的新单元格高度无效,则可能会出现运行时错误。
Pedro Borges 2014年

1
最佳答案。谢谢。
Eric Chen

1
我知道这个技巧适用于动态内容。静态也可以很好地工作。太简单了。
蚂蚁2015年

2
这确实有效,但是可以弥补一个遗漏的问题:如果要隐藏/显示的行包含日期选择器,则仅执行[self.tableView beginUpdates];否则,无需执行任何操作。[self.tableView endUpdates]; 隐藏它时仍会出现故障。为了消除故障,您应该使用[RowAnimation:UITableViewRowAnimationNone]调用[self.tableView reloadRowsAtIndexPaths:@ [indexPathOfTargetRow];还要注意的是,这里的行动画被“禁用”了。
克里斯

34

我的解决方案与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,节和行。

还要记住,像这样的方法的indexPath参数对于didSelectRowAtIndexPath:同一单元格将有所不同,具体取决于状态(即,隐藏单元格的数量)。因此,始终偏移任何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];
}

2
祝福你,你这个甜美可爱的人。
guptron

您是否找到了针对动画小故障的解决方案?对我而言,单元格之间的分隔线无法正确设置动画,并且id不使用任何动画,而要使用任何动画。很好的解决方案!
马克西米利安·科纳

我的问题是numberOfRowsInSection:只有在第一次加载表时才调用静态单元格。当我调用[self.tableView reloadData]- numberOfRowsInSection:永远不会再被调用。仅cellForRowAtIndexPath:被调用。我想念什么?
罗马

13
  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)
        }

}

迄今为止最好的解决方案!
derdida's

进行更改后添加tableView.reloadData(),这是完美的。节省了我很多更改解决方案的精力!谢谢
Shayan C

1
Swift 4不允许我使用let tableViewCell = super.tableView(tableView,cellForRowAtIndexPath: indexPath)。我假设它已被替换let tableViewCell = tableView.cellForRow(at: indexPath as IndexPath)
克利夫顿·拉布鲁姆

由于我在上使用静态单元格UITableViewController,因此没有任何UITableView委托方法。为了能够调用它heightForRow,我还需要其他方法吗?
克利夫顿·拉布鲁姆

@CliftonLabrum不,您只能覆盖此方法。
亚历山大·埃尔肖夫

11

我想出了一个替代方案,实际上隐藏了部分,并且不删除它们。我尝试了@ 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,因为将无法正确绘制边框。


1
我可能会使用NSMutableSethiddenSections替代。由于您主要测试成员资格,因此速度要快得多。
pixelfreak 2012年

好答案,奥斯丁。我投票赞成该答案,并将在以后的项目中用作参考。pixelfreak也NSMutableSet为for提供了一个很好的观点hiddenSections,尽管我知道您的回答要点比应该选择哪种类型的数据结构更具概念性。
BigSauce 2012年

10

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

示范项目

演示项目视频

要点:

  1. Use tableView:heightForRowAtIndexPath: 根据某些状态动态指定像元高度。
  2. 当状态变化时,通过调用显示/隐藏的动画单元格 tableView.beginUpdates();tableView.endUpdates()
  3. 不要tableView.cellForRowAtIndexPath:在里面打电话tableView:heightForRowAtIndexPath:。使用缓存的indexPath区分单元格。
  4. 不要隐藏细胞。而是在Xcode中设置“ Clip Subviews”属性。
  5. 使用自定义单元格(而不是普通单元格)来获得漂亮的隐藏动画。另外,对于像元高度== 0的情况,请正确处理“自动布局”。

我的博客中有更多信息(俄语)


1
这一点对我来说很重要:“不要隐藏单元格。而是在Xcode中设置“ Clip Subviews”属性。”
balkoth

8

是的,虽然目前我正为同一问题而苦苦挣扎,但绝对有可能。我设法隐藏了单元格,一切正常,但是我目前无法使它动画整齐。这是我发现的:

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

当切换开关时,我有一个选择器被调用,并且我设置了一个变量来指示我所处的状态。然后我调用:

[[self tableView] reloadData];

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

[cell setHidden:YES];

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

要删除空间,请重写tableView:heightForRowAtIndexPath:函数,并为应隐藏的行返回0。

您还需要重写tableView:numberOfRowsInSection:并返回该部分中的行数。您必须在这里做一些奇怪的事情,以便如果表是分组样式,则圆角会出现在正确的单元格上。在我的静态表中,该部分有完整的单元格集合,因此第一个单元格包含该选项,然后是1个单元格用于ON状态选项,另外2个单元格用于OFF状态选项,总共4个单元格。当该选项为ON时,我必须返回4,其中包括隐藏的选项,以便最后显示的选项带有一个圆角框。如果关闭该选项,则不会显示最后两个选项,因此我将返回2。这一切都感觉很笨拙。抱歉,如果不清楚,很难描述。仅为了说明设置,这是IB中表部分的构造:

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

因此,当该选项为ON时,表报告两行:

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

当该选项为OFF时,表格报告四行,分别是:

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

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

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

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

希望有人能够提出其他方法或动画的扩展方法,但这也许可以帮助您入门。我对缺少功能的超链接表示歉意,我将其放入,但由于我是一个相当新的用户,它们被垃圾邮件过滤器拒绝了。


我很确定您[[self tableView] reloadData];隐藏了牢房后应该再打一次电话
Shmidt

很抱歉,无法恢复此功能,但是您如何能够继承UITableViewController并将其用于静态单元格呢?Xcode不会让我。
丹妮·乔玛

Nessup,您不需要子类化UITableView。在情节提要中选择TableViewController,然后单击TableView。现在,您可以在动态/静态单元格之间进行选择。
Shmidt 2012年

1
我找到了如何为静态细胞隐藏/显示动画的解决方案。只需调用return [super tableView:tableView cellForRowAtIndexPath:indexPath];UITableViewController子类中创建静态细胞。索引路径是静态索引-不是动态索引–
k06a 2012年

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

1
tableView.reloadRows(at:, with:)如果在该行已经可见的情况下更改高度,则可能需要更新单元格。
Frost-Lee

5

好吧,经过一番尝试,我有一个不常见的答案。我正在使用“ 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) }

这将减少委托方法中的逻辑,并且您只需要关注您的业务需求。


4

由于自动布局问题,上述隐藏/显示单元格,更改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
}

即使在5年后,效果也很好!非常感谢。
施罗克韦尔

2020年,这是最大的解决方案。无需黑客。
mdonati

3

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

对于iOS 11,我发现Mohamed Saleh的答案的修改版本效果最好,并且基于Apple的文档进行了一些改进。它动画效果很好,避免了任何丑陋的破解或硬编码值,并使用了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)

苹果建议performBatchUpdatesbeginUpdates/endUpdates只要有可能。


1

我找到了一种为静态表中的单元格设置动画的解决方案。

// 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

1

迅速回答:

在TableViewController中添加以下方法:

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

如果tableView试图绘制您想要隐藏的单元格,则它将不会显示它,因为由于上述方法,其高度将被设置为0pt,其他所有内容均保持不变。

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


1

在> 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。


1

斯威夫特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
}

0

对于最简单的方案,当您在表格视图的最底部隐藏单元格时,可以在隐藏单元格之后调整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);
}


0

来自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;
}

0

当然可以。首先,返回要显示的单元格的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))
}

0

除了@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)
    }

}

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


0

我有一个更好的方法来动态隐藏静态单元格甚至部分,而无需任何技巧。

将行高设置为0可以隐藏行,但是如果您要隐藏整个节(即使您隐藏所有行也可以容纳一些空格),则此操作将无效。

我的方法是建立一个静态单元的节数组。然后,表视图的内容将由section数组驱动。

这是一些示例代码:

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身高了。

此代码也非常易于维护。例如,如果您要添加/删除更多的单元格或节。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.