UITableView rowHeight动画需要太长时间

时间:2014-02-20 14:59:29

标签: ios uitableview animation

我的桌面视图中rowHeight的更改动画有问题。动画在iPad 3(第一代视网膜)上花费很长时间(约3秒)。但是,当桌面视图靠近列表的中间到底部或减少时,如果我 展开 rowHeight,则只需要很长时间列表中间的rowHeight。当它位于顶部时,动画效果很好。注意事项:

  1. 我正在继承UITableView并重写setEditing:animated方法,这是我更改rowHeight的地方。
  2. 我尝试不使用tableView:heightForRowAtIndexPath:,因为我的表可以拥有用户想要的行数。如果导入数据,某些用户甚至可能拥有数十万行。
  3. 当用户将表格放入"编辑"模式,我希望行高增长一定量(目前由30.0f),其中我显示每个单元格的一系列选项(如#"删除","复制& #34;," print"," share"等。)
  4. 由于行高正在变化,我在rowHeight更改之前抓取最顶部显示的单元格的路径,然后在rowHeight更改后将tableview滚动到相应的路径,以便用户不会松开它们的位置。如果我根本不滚动,延迟会更好(可能是2.5秒而不是3秒),并且列表最终会在一个完全不同的地方开始。
  5. 如果我没有动画更改(又名:beginUpdates& endUpdates)而只是简单地调用reloadData,则更改是即时的。当然,那时没有动画。
  6. 我尝试使用[self reloadRowsAtIndexPaths:self.indexPathsForVisibleRows withRowAnimation:UITableViewRowAnimationAutomatic]无效(需要永久)。
  7. 我尝试过放置beginUpdates& endUpdates几乎在代码中的每个可能的位置,都没有效果。
  8. 我尝试过计算并直接设置contentOffset,但结果却产生了一些奇怪的效果,比如没有刷新tableCell等等。
  9. 我做了一些时间档案,发现大部分时间花在tableView:cellForRowAtIndexPath:上。所以我记录了动画期间调用tableView:cellForRowAtIndexPath:的次数:
    1. 没有scrollToRowAtIndexPath:atPosition:animated 59次
    2. 使用scrollToRowAtIndexPath:atPosition:animated 67次
    3. 使用reloadData代替beginUpdates& endUpdates 8次
  10. 这里是代码,非常简单,真的:

    - (void) setEditing:(BOOL)editing animated:(BOOL)animated{
        CGPoint point = CGPointMake(1, _sectionView.superview ? _sectionView.bounds.size.height + 1 + self.bounds.origin.y : 1 + self.bounds.origin.y);
        NSIndexPath *path = [self indexPathForRowAtPoint:point];
        [super setEditing:editing animated:animated];
        CGFloat rowHeight = self.viewType.viewHeight.floatValue + (self.editing ? FlxRecordTableCellEditingHeight : 0);
        self.rowHeight = rowHeight;
        [self beginUpdates];
        [self endUpdates];
    //    [self reloadData];
        [self scrollToRowAtIndexPath:path atScrollPosition:UITableViewScrollPositionTop animated:NO];
    //    [self reloadRowsAtIndexPaths:self.indexPathsForVisibleRows withRowAnimation:UITableViewRowAnimationAutomatic];
    }
    

    当更改rowHeight时,UITableView会计算当前contentOffset的新行,然后尝试设置这些新行的动画(包括其间的所有行)即使我告诉它移动到它开始的相同单元格。我怀疑如果我要增加rowHeight的更改(例如,从30.0f45.0f),问题会变得更糟,因为UITableView必须为更多行设置动画更改。我想要的是UITableView首先移动到新单元格然后仅为那些单元格设置更改动画。但是,我似乎找不到办法做到这一点。

    更新

    神圣的{favorite_euphamism}! ......我一直试图提高tableView:cellForRowAtIndexPath效率,但无济于事。所以我单独计算了tableView:cellForRowAtIndexPath结束创建新单元格的次数(而不是重复使用它们)。在动画期间,UITableView并不仅仅需要59到67次请求单元格,它通过返回{创建 59-67 新单元格 {1}} nil。难怪它花了这么长时间......而且它也惹恼了我的记忆(感谢Xcode 5展示了......)。虽然我尽可能多地完成了我的细胞效率,但它们仍然是复杂的视图,并且绝对 设计用于那么多的创作。要解决这个问题......

    任何帮助或想法将不胜感激。谢谢!

1 个答案:

答案 0 :(得分:0)

所以,我提出的解决方案是最好的黑客,但它暂时正在工作。根据{{​​3}},Apple可能已经解决了即将推出的iOS 7.1更新问题,但我还没有搞砸测试版,所以我无法确认。

不幸的是,我被迫实施tableView:heightForRowAtIndexPath:。我不想,但幸运的是大多数人已经更新到iOS 7,我可以在estimatedRowHeight上有条件地使用UITableView属性(仅限iOS 7)来缓解iOS 7大表的性能问题......每一个人都被搞砸了。我接近将我的应用程序设为“仅限iOS 7”,因此长时间(或非常多用户)不会出现问题。

我在课程中添加了3个新的iVar:CGFloat _rowHeightCGFloat _imminentRowHeightNSIndexPath *_anchorPath。默认情况下返回_rowHeight变量。但是,如果设置了_anchorPath,则tableView:heightForRowAtIndexPath:会在_imminentRowHeight时有条件地返回indexPath.row >= _anchorPath.row。这样可以在转换期间保持contentOffset的{​​{1}}相同,以便_anchorPath不会尝试通过几十个tableview单元格进行动画制作,这是原始问题:

UITableView

我创建了一种新方法来分离我的逻辑- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ if (_anchorPath){ return indexPath.row >= _anchorPath.row ? _imminentRowHeight : _rowHeight; } return _rowHeight; } 。我想再次指出这是updateRowHeight的子类,所以如果您从视图控制器执行此操作,请将UITableView替换为您的self iVar:

_tableView

有些注意事项:

  1. 如果不需要更新,我会提前退出方法。如果行高未更改或未找到anchorPath,则会发生这种情况,如果没有显示行或表尚未加载,则会发生这种情况。 - (void) updateRowHeight{ CGFloat cellHeight = self.viewType.viewHeight.floatValue; CGPoint anchorPoint = CGPointMake(1, _sectionView.superview ? _sectionView.bounds.size.height + 1 + self.bounds.origin.y : 1 + self.bounds.origin.y); _anchorPath = [self indexPathForRowAtPoint:anchorPoint]; _imminentRowHeight = cellHeight + (self.editing ? FlxRecordTableCellEditingHeight : 0); if (!_anchorPath){ _rowHeight = _imminentRowHeight; if ([self respondsToSelector:@selector(estimatedRowHeight)]){ self.estimatedRowHeight = _rowHeight; } return; } if (_imminentRowHeight == _rowHeight) return; [CATransaction begin]; [CATransaction setCompletionBlock:^{ _rowHeight = _imminentRowHeight; NSIndexPath *anchor = _anchorPath; _anchorPath = nil; if ([self respondsToSelector:@selector(estimatedRowHeight)]){ self.estimatedRowHeight = _rowHeight; } [self reloadData]; [self scrollToRowAtIndexPath:anchor atScrollPosition:UITableViewScrollPositionTop animated:NO]; }]; [self beginUpdates]; [self endUpdates]; //We must scroll the anchor Path into the top position so that when we reload the table data positions don't change [self scrollToRowAtIndexPath:_anchorPath atScrollPosition:UITableViewScrollPositionTop animated:YES]; [CATransaction commit]; } 必须在这里做很多工作,所以除非必要,否则最好不要做这项工作。
  2. 我使用UITableView来设置动画上下文,以便我可以将完成块附加到它上面。 CATransaction将使用当前动画上下文(如果有),否则它将创建自己的...非常方便。
  3. 我将锚点路径(动画)滚动到最高位置,以便在重新加载表格数据时表格视图不会“跳转”。再次,在重新加载数据后,我再次滚动(没有动画),以便表格看起来与重新加载之前完全相同。
  4. 我必须重新加载表格,因为我只更改了锚点路径“下方”的单元格的行高。在我重新加载之前,begin/endUpdates认为锚点路径“上方”的所有内容都具有前一行(和不正确的行)高度。这就是我在重新加载表之前设置UITableView_rowHeight = _imminentRowHeight;的原因。然后我必须在重新加载后滚动到锚点路径(不是动画),因为锚点路径的偏移量已经改变,因为所有先前的行都有新的行高。
  5. 当表重新加载时,有一个非常轻微的“闪烁”。对于我的应用程序至少,只有单元格文本“闪烁”,那是因为我正在使用异步绘制文本的自定义绘图例程。因此,其他人可能根本没有任何闪烁。对我来说,效果是如此轻微,我可能会忽略它。我正在考虑显示叠加层的想法,但由于我们谈论的是整个屏幕内容,我怀疑它会运作良好。