ios - 将 TableView 与许多自定义单元格和自动布局一起使用

标签 ios objective-c uitableview autolayout custom-cell

我想重构一些代码以获得更好的性能,但我的问题是我不确定如何去做。目前我有一个 UIViewController 上面有一个 UIScrollView

我还有 20 个不同的 View (每个 View 都有自己的 .h 和 .m 文件)可以完全动态地放置在我的 UIScrollView 上。每次我启动 UIViewController 时,我都会向我的服务器发送一个请求,然后我得到响应,然后我知道我必须在 UIScrollView 上放置多少个 View 。 所以你可以想象,当我的 UIScrollView 上有很多不同的 View 时,在用户最终可以与它们交互之前,所有 View 都已完全加载需要几秒钟。

所以我的想法是用 UITableView 替换 UIScrollView 并将所有 CustomViews (UIViews) 更改为 Custom UITableViewCells。因此只有可见的 Cell 会在第一次启动时加载!

知道我有几个问题。

  1. 目前,我的 CustomViews 中的大部分代码都是使用 Frames 构建的,但我想将其完全更改为 Autolayout,我不想认为用IB(xib 文件...)构建它们是有意义的。所以我必须在代码中完成整个 Autolayout 的工作?

  2. 有些自定义 View 非常大,因此它们变得非常高,而有些可能非常小。我担心的是滚动性能会非常糟糕......因为我不能真正使用 estimatedRowHeight(一个例子:有时一个单元格可以获得 1000.0f 的高度而下一个单元格只有 40.0f)。结合自动布局和我必须等待服务器响应到达的时间,我认为这对用户来说真的很烦人。

  3. 最多可以有 20 个不同!!自定义行,在这种情况下使用 UITableView 真的有意义吗?正如我之前提到的,它们的大小和内容都非常不同!

这是我的新代码的一小部分:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.node.blocks count];
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
GTBlockView *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];


GFBlock *block = [self.node.blocks objectAtIndex:indexPath.row];

//createInterfaceforBlock -- Here the Cell gets called and the Content and the Size gets defined
cell = [[GTAppController sharedInstance]  createInterfaceForBlock:block];

// Make sure the constraints have been added to this cell, since it may have just been created from scratch
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];

return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{

//GTBlockView is the SuperView of all my Custom Cells
GTBlockView *cell = [self.offscreenCells objectForKey:CellIdentifier];

if (!cell)
{
    cell = [[GTBlockView alloc] init];

    [self.offscreenCells setObject:cell forKey:CellIdentifier];
}

 GFBlock *block = [self.node.blocks objectAtIndex:indexPath.row];

//createInterfaceforBlock -- Here the Cell gets called and the Content and the Size gets defined
cell = [[GTAppController sharedInstance] createInterfaceForBlock:block];

// Make sure the constraints have been added to this cell, since it may have just been created from scratch
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];


cell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(tableView.bounds), CGRectGetHeight(cell.bounds));

[cell setNeedsLayout];
[cell layoutIfNeeded];

// Get the actual height required for the cell
CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;


height += 1;


return height;
}

也许你们中的一些人有更好的想法或一些好的资源?

最佳答案

在我自己的应用程序中,我完全按照您的想法做了 - 我首先沿着 UIScrollview 路线走下去,然后我改为具有多种自定义单元格的 UITableview。它确实非常有意义并且非常值得 - 我从 uitableview 获得了巨大的性能提升。 UIScrollview 的主要问题之一是它将为您的 contentView 中的所有内容制定自动布局,正如您所说,这可能需要几秒钟,但 UITableview 会更快更有效地处理这个问题。所以 - 去吧。

我强烈建议您为每个自定义单元格使用唯一的 XIB 文件。分别在每一个中进行自动布局,这样您就更有可能避免出现问题。编程约束更难维护,自动布局通常具有挑战性。

为了使其全部正常工作,我执行了以下操作:首先我有一个 UITableviewCell 的子类,它是所有其他单元格对象的父类。在我的例子中,这被称为 SNFormTableCell (UITableviewCell)。然后所有其他单元格对象都基于此类。在我的 cellForRowAtIndexPath 方法中,我这样做:

ReportItem *objectForCell = [self.reportSet reportItemForSection:indexPath.section andRow:indexPath.row]; //my personal data class - just contains the cell data I need
NSString *identifier = [self getNibNameAndReusableIdentifierNameForObjectType:objectForCell.cellType.integerValue];
SNFormTableCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell)
{
    [self registerNib:[UINib nibWithNibName:identifier bundle:nil] forCellReuseIdentifier:identifier];
    cell = [tableView dequeueReusableCellWithIdentifier:identifier];
    cell.contentView.clipsToBounds = YES;
}
[cell setSnFormTableCellDelegate:self];  //i have a delegate that calls back to the tableview when cells are interacted with
cell.reportItem = objectForCell; //put the data object onto the cell to do with as the cell requires
[cell refreshUI];  //update the UI using the data - this is over-ridden by the various subclasses of the cell

那里的方法称为 getNibNameAndReusableIdentifierNameForObjectType .. 看起来像这样(只获取我们需要的标识符以供 nib 和重用):

- (NSString*) getNibNameAndReusableIdentifierNameForObjectType:(SNFormTableObjectType)objectType {
if (objectType == SNFormTableObjectTypeBoolean) return @"SNBooleanCell";
if (objectType == SNFormTableObjectTypeDatePicker) return @"SNDatePickerCell";
if (objectType == SNFormTableObjectTypeDropDown) return @"SNDropDownCell";
if (objectType == SNFormTableObjectTypeDropDownPlusSingleLineText) return @"SNDropDownPlusSingleLineTextCell";
... etc
}

最后,父单元格类有一个方法叫做 -(void) refreshUI。所以我把数据对象放到那个单元格上——它包含我可能需要的所有数据。子类以它们自己的特定方式覆盖此 refreshUI 方法,以根据需要使用数据。

重申一下,我从这条道路上获得了巨大的 yield 。包含大量内容的 ScrollView ,需要 5 秒或更长时间来加载 Nib 和计算自动布局(也在主线程上,使应用程序无响应),将立即出现在 UITableview 版本上。所以去吧。如果您需要有关如何操作的更多详细信息,请告诉我。

关于ios - 将 TableView 与许多自定义单元格和自动布局一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32050317/

相关文章:

ios - 委托(delegate)如何知道在有多个一致性的地方调用函数

ios - iOS kABPersonModificationDateProperty 的奇怪行为,似乎一直在更新

ios - 检查 Objective-C 中的日期格式样式

ios - 应用程序在后台时是否可以使用 NSFileManager 的 `copyItemAtURL:toURL:error:` 方法?

ios ARC 表访问错误

iphone - 在 UITableViewCell 中启用/禁用编辑模式

ios - Facebook SDK 不是动态库

ios - 如何在 Swift 中检测图像中的条形码?

ios - UITableView 单元格中的动态形状 (Swift)

ios - iOS中如何完成Segmented Control的文本显示?