UITableView set to static cells. Is it possible to hide some of the cells programmatically?

UITableView set to static cells.

Is it possible to hide some of the cells programmatically?

103753 次浏览

是的,这绝对是可能的,尽管我现在正在为同样的问题而挣扎。我已经设法让细胞隐藏起来,一切工作正常,但目前我不能使事情动画整齐。以下是我的发现:

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

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

[[self tableView] reloadData];

我重写 TableView: will DisplayCell: forRowAtIndexPath:函数,如果细胞应该是隐藏的,我这样做:

[cell setHidden:YES];

隐藏单元格及其内容,但不移除其占用的空间。

若要删除空格,请重写 TableView: heightForRowAtIndexPath:函数,并对应该隐藏的行返回0。

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

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

因此,当选项为 ON 时,表将报告两行,这两行是:

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

当选项为 OFF 时,表将报告四行,它们是:

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

这种方法感觉不正确有几个原因,它只是到目前为止,我已经与我的实验,所以请让我知道,如果你找到一个更好的方法。到目前为止,我观察到的问题有:

  • 如果告诉表行数不同于可能包含在底层数据中的行数,那么感觉是错误的。

  • 我似乎无法激活这种变化。我已经尝试使用 ReloadSections: withRowAnimation:代替 reloadData,但结果似乎没有意义,我仍在努力让它工作。目前看来,tableView 没有更新正确的行,因此一个行仍然隐藏,应该显示,并在第一行下留下一个空白。我认为这可能与关于基础数据的第一点有关。

希望有人能够建议替代方法或者如何使用动画进行扩展,但是这可能会让你开始。我很抱歉没有超链接到函数,我把他们,但他们被垃圾邮件过滤器拒绝,因为我是一个相当新的用户。

我的解决方案与加雷思的方向相似,尽管我的做法有所不同。

开始了:

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];
}

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

我找到了一个在静态表中隐藏动画细胞的解决方案。

// 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];
}

关于 UISswitch 价值变化的一个 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 和 UITableViewCommittee 方法:

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

你正在寻找这个解决方案:

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 解决方案,并允许您动画更改和隐藏整个部分

在 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 中的“剪辑子视图”以查看要隐藏的单元格。您隐藏的单元格需要有 ClipToBound = YES。否则文本将堆积在 UITableView 中。

最好的方法如下面的博客所述 Http://ali-reynolds.com/2013/06/29/hide-cells-in-static-table-view/

将静态表格视图设计为正常的 Interface Builder- 所有可能隐藏的细胞。但有一件事你 必须对每个要隐藏的潜在单元格执行 单元格的“剪辑子视图”属性,否则为 细胞不会消失,当你试图隐藏它(缩小它的 身高(稍后详述)。

所以,你在牢房里有一个开关,这个开关应该是藏起来的 并显示一些静态细胞。连接到 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;
}

就这样,打开开关,细胞隐藏起来,然后重新出现 漂亮,流畅的动画。

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

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

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

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

你当然可以。首先,返回 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))
}

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

对于一个简单的静态表,对我来说最有效的方法是:

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

下面是我的表视图控制器中的一个例子:

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

事实证明,您可以在静态 UITableView 中隐藏和显示单元格-并使用动画。而且也不是那么难完成。

演示项目

演示项目视频

要点:

  1. Use tableView:heightForRowAtIndexPath:根据某种状态动态指定单元格高度。
  2. 当状态改变时,通过调用 tableView.beginUpdates();tableView.endUpdates()显示/隐藏动画单元格
  3. 不要在 tableView:heightForRowAtIndexPath:中调用 tableView.cellForRowAtIndexPath:。使用缓存的索引路径来区分单元格。
  4. 不要隐藏单元格,而是在 Xcode 设置“剪辑子视图”属性。
  5. 使用自定义单元格(不是普通等) ,以获得一个很好的隐藏动画。另外,当单元格高度 = = 0时,正确处理自动布局。

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

迅速中回答:

在 TableViewController 中添加以下方法:

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

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

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

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

从故事板创建一个出口链接到静态单元格。

@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. 在设计器中,为要隐藏的单元格创建一个出口。例如,您希望隐藏“ cellOne”,所以在 viewDidLoad ()中执行此操作

CellOneOutlet.hide = true

现在重写下面的方法,检查哪个单元格状态是隐藏的,并为这些单元格返回高度0。这是可以用 Swift 在静态 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)
}


}

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


}

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

简单的 iOS 11与 IB/故事板兼容方法

对于 iOS11,我发现一个修改过的 穆罕默德 · 萨利赫的回答版本效果最好,在苹果文档的基础上做了一些改进。它动画很好,避免任何丑陋的黑客或硬编码值,和 使用已经在 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)

苹果公司尽可能推荐 performBatchUpdates优于 beginUpdates/endUpdates

迅捷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
}

正如贾斯塔斯的回答,但对于斯威夫特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. 为视图控制器创建一个 IBOutlet。 @IBOutlet weak var myCell: UITableViewCell!

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

覆盖 func viewDidLoad (){ ViewDidLoad () 隐藏 = 真实 }

  1. 在委托方法中:

覆盖 func tableView (_ tableView: UITableView,heightForRowAt indexPath: IndexPath)-> CGFloat { Let cell = super.tableView (tableView,cellForRowAt: indexPath) 看守! 牢房 返回0 } 返回 super.tableView (tableView,heightForRowAt: indexPath) }

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

我有一个更好的方法来隐藏静态单元格,甚至动态部分没有任何黑客。

将行高设置为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高度了。

此代码也很容易维护。例如,如果您想添加/删除更多的单元格或节。

类似地,可以创建节头标题数组和节脚标题数组来动态配置节标题。