gpt4 book ai didi

ios - UITableView rowHeight 动画耗时太长

转载 作者:可可西里 更新时间:2023-11-01 06:15:18 25 4
gpt4 key购买 nike

我在为我的 tableview 设置 rowHeight 更改动画时遇到问题。动画在 iPad 3(第一代视网膜)上需要很长时间(大约 3 秒)。但是,如果我在 tableview 靠近列表的中到底部时扩展 rowHeight 或减少列表中间的 rowHeight ,则只需要这么长时间。当它位于顶部时,动画效果很好。注意事项:

  • 我正在继承 UITableView 并覆盖 setEditing:animated 方法,这是我更改 rowHeight 的地方。
  • 我尽量不使用 tableView:heightForRowAtIndexPath:,因为我的表可以有用户想要的行数。有些用户如果导入数据,甚至可能有几十万行。
  • 当用户将表格置于“编辑”模式时,我希望行高增加一定数量(目前由 30.0f ),在那里我为每个单元格显示一系列选项(就像“删除”,“复制” 、“打印”、“共享”等)。
  • 因为行高在变化,所以我在 rowHeight 更改之前抓取最上面显示的单元格的路径,然后在 rowHeight 更改后将 tableview 滚动到适当的路径,这样用户就不会丢失他们的位置。如果我根本不滚动,延迟会稍微好一些(可能是 2.5 秒而不是 3 秒),并且列表最终会出现在与开始时完全不同的地方。
  • 如果我不为更改设置动画(又名:beginUpdates & endUpdates ),而只是调用 reloadData ,则更改是即时的。当然,那时没有动画。
  • 我试过使用 [self reloadRowsAtIndexPaths:self.indexPathsForVisibleRows withRowAnimation:UITableViewRowAnimationAutomatic] 没有效果(它需要永远)。
  • 我已经尝试将 beginUpdatesendUpdates 放在代码中几乎所有可以想象的位置,但都没有效果。
  • 我试过计算并直接设置 contentOffset ,但最终得到了一些奇怪的效果,比如 tableCells 没有被刷新等。
  • 我做了一些时间分析,发现大部分时间都花在了 tableView:cellForRowAtIndexPath: 上。所以我记录了动画期间 tableView:cellForRowAtIndexPath: 被调用的次数:
  • 没有 scrollToRowAtIndexPath:atPosition:animated : 59 次
  • 使用 scrollToRowAtIndexPath:atPosition:animated : 67 次
  • 使用 reloadData 而不是 beginUpdates & endUpdates : 8 次

  • 这是代码,非常简单,实际上:
    - (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 次,它还通过为 nil 返回 dequeueReusableCellWithIdentifier 来创建 59-67 新单元格。难怪它花了这么长时间......而且它也刺激了我的内存(感谢 Xcode 5 显示......)。虽然我已尽我所能使我的单元格高效,但它们仍然是复杂的 View ,绝对不是为那么多创作而设计的。一定有办法解决这个问题...

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

    最佳答案

    所以,我想出的解决方案充其量只是一个黑客,但它暂时有效。根据 Nikolai Ruhe ,Apple 可能已经在即将发布的 iOS 7.1 更新中解决了这个问题,但我还没有搞砸测试版,所以我无法确认。

    不幸的是,我被迫实现 tableView:heightForRowAtIndexPath: 。我不想,但幸运的是大多数人已经更新到 iOS 7,我可以有条件地使用 estimatedRowHeight 上的 UITableView 属性(仅限 iOS 7)来缓解 iOS 7 大表的性能问题......被搞砸了。我即将使我的应用程序成为“仅适用于 iOS 7”,因此它不会成为长期问题(或对很多用户而言)。

    我在类(class)中添加了 3 个新 iVar: CGFloat _rowHeightCGFloat _imminentRowHeightNSIndexPath *_anchorPath_rowHeight 变量默认返回。但是,如果 _anchorPath 已设置,则 tableView:heightForRowAtIndexPath: 将有条件地返回 _imminentRowHeight 如果 indexPath.row >= _anchorPath.row 。这在转换期间保持 contentOffset_anchorPath 相同,以便 UITableView 不会尝试通过几十个 tableview 单元格进行动画处理,这是原始问题:

    - (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    if (_anchorPath){
    return indexPath.row >= _anchorPath.row ? _imminentRowHeight : _rowHeight;
    }
    return _rowHeight;
    }

    我创建了一个新方法来分离我的逻辑 updateRowHeight 。我想再次指出这是 UITableView 的子类,因此如果您从 View Controller 执行此操作,请将 self 替换为您的 _tableView iVar:
    - (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];
    }

    一些注意事项:
  • 如果不需要更新,我会尽早退出该方法。如果行高未更改或未找到 anchorPath,则会发生这种情况,如果没有显示行或表尚未加载,则会发生这种情况。 UITableView 这里要做很多工作,所以除非必要,否则最好不要做这项工作。
  • 我使用 CATransaction 设置动画上下文,以便我可以将完成块附加到它。如果可用,begin/endUpdates 将使用当前动画上下文,否则它将创建自己的......非常方便。
  • 我将 anchor 路径滚动(动画)到顶部位置,以便在我重新加载表格数据时表格 View 不会“跳跃”。同样,在重新加载数据后,我再次滚动(没有动画),以便表格看起来与重新加载之前完全相同。
  • 我必须重新加载表格,因为我只更改了 anchor 路径“下方”单元格的行高。在我重新加载之前,UITableView 认为 anchor 路径“上方”的所有内容都具有先前(且不正确)的行高。这就是我在重新加载表之前设置 _rowHeight = _imminentRowHeight;_anchorPath = nil; 的原因。我必须在重新加载后滚动到 anchor 路径(不是动画),因为 anchor 路径的偏移量已经改变,因为所有以前的行都具有新的行高。
  • 表重新加载时有一个非常轻微的“闪烁”。至少对于我的应用程序,只有单元格文本“闪烁”,这是因为我正在使用异步绘制文本的自定义绘图例程。因此,其他人可能根本不会有任何闪烁。对我来说,这种影响很小,我可能会忽略它。我正在考虑显示叠加层的想法,但由于我们谈论的是整个屏幕的内容,我怀疑它是否能正常工作。
  • 关于ios - UITableView rowHeight 动画耗时太长,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21911488/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com