【问题标题】:UITableView bouncing back to the top of a section when calling reloadRowsAtIndexPaths调用 reloadRowsAtIndexPaths 时 UITableView 弹回部分顶部
【发布时间】:2023-04-02 18:30:01
【问题描述】:

当用户点击我的某一行中的按钮时,我正在更新该行的基础模型,然后为给定行调用 reloadRowsAtIndexPaths(即单行重新加载)。

- (IBAction)handleCompleteTouchEvent:(UIButton *)sender {
    NSIndexPath *indexPath = [self.tableView indexPathForView:sender];
    id item = [self dataForIndexPath:indexPath];

    if ([item respondsToSelector:@selector(completed)]) {
        // toogle completed value
        BOOL completed = ![[item valueForKey:@"completed"] boolValue];
        [item setValue:[NSNumber numberWithBool:completed] forKey:@"completed"];

        [self.tableView beginUpdates];
        [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
        [self.tableView endUpdates];
    }
}

问题是表格视图在进行此调用后反弹回该部分的顶部。如何防止这种情况发生并保持滚动位置不变?

【问题讨论】:

  • 代码看起来不错。你能分享更多与问题相关的代码吗?如果您的视图控制器调用[self.tableView reloadData];,代码中是否有任何位置?
  • 我添加了更多代码来展示整个方法。一旦调用 reloadRowsAtIndexPaths,表格会自动滚动到节的顶部,但仅当节标题离开屏幕时。单元格创建或节标题(只是一个字符串)没有什么特别之处。
  • @Keenle 我没有执行任何 reloadData 或类似的操作。此外,文档中没有任何关于弹跳到 reloadRows 部分顶部的内容。我以前从未注意到此功能,但我通常不会在单元格本身内进行数据更改操作,因此这对我来说是一种新型交互方式。
  • 尝试检查从indexPathForView 收到的indexPath 的值。可以是nil。如果是这样,它一定会导致滚动到顶部。
  • @Keenle indexPath 是正确的。这是我检查的第一件事。此外,它不会反弹到表的顶部 (0,0)。它反弹到部分的顶部 (1,0)。

标签: ios objective-c uitableview ios7


【解决方案1】:

啊哈!我找到了问题,我将为将来遇到这个问题的可怜人回答我自己的问题。

我所有的单元格都有可变高度,所以我在 UITableViewDelegate 中使用了新的 iOS7 方法,认为它可能会加快渲染时间(并不是我真的需要它):

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath;

不管怎样,实现这个方法有一个恶毒的副作用,就是调用的时候,表格会反弹到section的顶部:

[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];

为了解决弹跳问题,我刚刚删除了估计的HeightForRowAtIndexPath 方法的覆盖,现在一切正常。终于开心了。

【讨论】:

  • 你好@xsee,如果我使用autoLayout,如果我不使用extimatedRowHeight,那么添加时会出现问题并且行会缩小
  • 我有同样的问题,除了我实际上想使用estimatedRowHeight。我发现通过将estimatedRowHeight 设置为大于单元格实际高度的数字似乎可以稍微改善行为(表格视图只滚动一点)。
  • 这个问题没有真正的解决方案吗?这似乎是苹果的一个错误?
  • 在iOS8中使用UITableViewAutomaticDimension时需要estimatedRowHeight。
  • 我在viewDidLoad 中设置了estimatedRowHeight = tableView.rowHeight,这似乎有点帮助。我也在使用UITableViewAutomaticDimension
【解决方案2】:

这对我有用。

UIView.setAnimationsEnabled(false)
tableView.reloadRows(at: [...], with: .none)
UIView.setAnimationsEnabled(true)

【讨论】:

    【解决方案3】:

    斯威夫特 4.2

    这可以在您想要删除动画的任何地方工作。 在重新加载表格、表格部分或任何行时

     UIView.performWithoutAnimation({
                    cell.configureSelection(isSelected: true)
                    tableView.reloadSections([1], with: .none)
                    tableView.allowsSelection =  false
    
                })
    

    【讨论】:

      【解决方案4】:

      您应该能够通过直接更改单元格内容来做您想做的事情。例如,如果您使用基类 UITableViewCell 并且模型中的数据是 NSString,您在表格视图单元格中显示,您可以执行以下操作(在更改数据模型后)而不是调用 @ 987654323@:

      UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
      UILabel *label = [cell textLabel];
      label.text = @"New Value";
      

      如果您使用的是 UITableViewCell 的自定义子类,则大致相同,只是需要通过 contentView 属性访问单元格的视图。

      【讨论】:

      • 这个解决方案有效,但我不喜欢它。想象一下,如果我想根据数据模型的更改来翻转整个单元原型。如果不重新加载行,我将无法做到这一点,但随后我又回到了“反弹到部分顶部”的问题。如果我无法为重新加载的问题找到更好的答案(或解决方法),那么我会接受这个答案。谢谢。
      【解决方案5】:

      可以将单元格放在它自己的部分并调用重新加载部分:

      [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationFade];
      

      这似乎可以部分解决问题。不是最干净的方法,但它可能对你有用。

      【讨论】:

        【解决方案6】:

        在我的类似情况下,我不得不调整方法的实现

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

        我的身高被重置的地方。因此,我没有为每个单元格重置高度,而是只更新了 reloadRowsAtIndexPaths 调用的受影响单元格。

        【讨论】:

          【解决方案7】:

          如果您知道单元格的最小高度,则必须在设置estimatedRowHeight 时指定。正如我之前在某处读到的那样,我将它设置为 1,任何高于 0 的值都足以达到目的,但这是罪魁祸首。

          当我将它设置为 44(这是我的单元格可以具有的最小高度)时,一切正常。

          动态高度也可以正常工作,此修复没有问题。

          【讨论】:

            【解决方案8】:

            建立 xsee 的答案 - 我已将界面生成器中的Estimate 设置为“自动”。我将其更改为另一个数字,它开始工作。我将Row Height 保持为自动。

            【讨论】:

              【解决方案9】:

              我有同样的问题。我最终只是在更新我的数据/单元格之后调用 tableView.reloadData() 并且它没有弹回顶部/数据已更新到位 - 仅供参考

              【讨论】:

                【解决方案10】:

                Swift 5 / iOS 14 为我解决了这个问题:

                UIView.performWithoutAnimation({
                   self.tableView.reloadRows(at: [self.idxTouched], with: .none)
                })
                

                【讨论】:

                  猜你喜欢
                  • 2023-04-07
                  • 1970-01-01
                  • 2018-11-15
                  • 2023-04-07
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2013-11-04
                  相关资源
                  最近更新 更多