将TableView与许多自定义单元格和自动布局

时间:2015-08-17 12:22:58

标签: ios objective-c uitableview autolayout custom-cell

我想重构一些代码以获得更好的性能,但我的问题是我不知道该怎么做。在片刻,我有一个UIViewController,上面有UIScrollView

我还有20个不同的视图(每个视图都有.h和.m文件)可以完全动态地放在我的UIScrollView上。每次我开始UIViewController我向我的服务器发送请求然后我得到响应,然后我知道我必须在UIScrollView上放置多少视图。 所以你可以想象,当我的UIScrollView上有很多不同的观点,因为在用户最终可以与他们进行交互之前,因为观察者已经完全加载,所以需要几秒钟。

所以我的想法是用UIScrollView替换UITableView并将所有自定义视图(UIViews)更改为自定义UITableViewCells。所以在第一次启动时只会加载可见的单元格!

知道我有几个问题。

  1. 在片刻中,我的CustomViews中的大多数代码都是使用Frames构建的,但我想将其完全更改为Autolayout,我认为构建它没有意义它们都带有IB(xib文件......)。所以我必须在代码中完成整个Autolayout Stuff?

  2. 一些自定义视图真的很大,所以它们变得非常高,有些可能非常小。我担心的是滚动Perfomance会非常糟糕...因为我无法真正使用estimatedRowHeight(例如:有时一个Cell可以获得1000.0f的高度而下一个单元只有40.0f)。并且可以组合使用使用Autolayout和时间我必须等到我的服务器到达响应时,我认为这对用户来说真的很烦人。

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

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

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

    也许有些人有更好的想法或一些好的来源?

1 个答案:

答案 0 :(得分:1)

我完全按照你自己的应用程序思考 - 我首先沿着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方法,以便根据需要使用数据。

为了重新进行迭代,我从这条路线上获得了极大的收获。具有大量内容的滚动视图,花费5秒或更长时间来加载笔尖并计算自动布局(在主线程上,使应用程序无响应),将立即显示在UITableview版本上。所以去吧。如果您需要更多详细信息,请与我联系。