【问题标题】:UITableView Scrolls to Top on Cell RefreshUITableView 在单元格刷新时滚动到顶部
【发布时间】:2015-07-18 11:35:13
【问题描述】:

我有一个 UITableView,它的单元格动态调整大小以适应其中的 UITextView。每当键入一个键时,单元格都会检查计算的高度是否增加,就像换行一样,因此它可以告诉表格单元格的高度需要重新计算。我用这段代码做到这一点。

- (void) createNoteCellViewDidUpdate: (CreateNoteCell*) cell {

    CGFloat newHeight = [self tableView:self.tableView heightForRowAtIndexPath:CreateNoteCellIndexPath];
    if (newHeight != CGRectGetHeight(cell.contentView.frame)) {
        [self.tableView beginUpdates];
        [self.tableView endUpdates]; // <- HERE IS WHERE THE CONTENT OFFSET CHANGES
    }
}

调整大小和表格边界符合预期。但是,它不仅会为高度变化设置动画,还可以滚动到顶部。这可以在这里看到,当按下返回键时。

通过键值观察,我发现当滚动视图的 contentSize 发生变化时,滚动视图的 contentOffset 正在设置。并且在调用 endUpdates 方法时 contentSize 会发生多次变化。当它改变时,它会从正常高度变为相当大的高度,然后又回到正常高度。我想知道它是否会因此而达到顶峰。我不知道从这里去哪里。

【问题讨论】:

  • 问题 - 为什么要调整表格视图的大小而不是调整单元格的大小?通常,tableview 的框架保持不变,内容会发生变化。
  • 不,我没有触及 Table View 框架或边界。我通过告诉表格视图重新计算单元格的所有高度来调整单元格的大小。

标签: ios objective-c uitableview uiscrollview uitextview


【解决方案1】:

哇,Josh Gafni 的回答帮了大忙;他值得一票。我的解决方案是基于他的。这仍然感觉像是一个 hack,所以如果有人还有更好的方法来做到这一点,我仍然很感兴趣。

首先我保存内容偏移量,然后开始更新。

CGPoint offset = self.tableView.contentOffset;
[self.tableView beginUpdates];
[self.tableView endUpdates];

这会为单元格的高度变化设置动画并调整所有帧以适应约束。

接下来,我从 tableView 的图层中删除所有动画,因此动画到顶部停止。然后我将 contentOffst 重置为之前的状态。

[self.tableView.layer removeAllAnimations];
[self.tableView setContentOffset:offset animated:NO];

最后,我让 tableView 处理动画向下滚动,这样单元格的底部就在键盘的正上方。

[self.tableView scrollToRowAtIndexPath:CreateNoteCellIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];

瞧,它运作良好。

【讨论】:

  • 我遇到了几乎完全相同的问题,但到目前为止还没有让这个解决方案发挥作用。我想知道,您是否正在做任何事情来确保您的 UITextView 单元格出现在键盘上方(例如更新 contentInset)?另外,您是否发现此解决方案的任何改进?谢谢!
  • 谢谢,正是我需要的。
  • 如果我可以让 Tinder 超级喜欢这篇文章,我会的。
【解决方案2】:

这是我完美运行的 UITableView 扩展。在斯威夫特 2.1 中。基于接受的答案。

extension UITableView
{
    func reloadDataAnimatedKeepingOffset()
    {
        let offset = contentOffset
        UIView.setAnimationsEnabled(false)
        beginUpdates()
        endUpdates()
        UIView.setAnimationsEnabled(true)
        layoutIfNeeded()
        contentOffset = offset
    }
}

【讨论】:

  • 这就是我要找的 'UIView.setAnimationsEnabled(...)'
【解决方案3】:

只是猜测...

在进行任何更改之前保存 uitableview 的 contentOffset。之后再设置。

CGFloat contentOffset = self.tableView.contentOffset;

然后在更改之后

self.tableView.contentOffset = contentOffset;

【讨论】:

  • 是的,但这有一个问题,contentOffset 是由 ScrollView 设置的,然后由我设置。所以动画开始把它带到顶部,然后我在动画中间把它带回来。所以它会向上动画,然后向下动画,这在高度占据整个屏幕后变得非常烦人。
  • 一个想法(有点小技巧)可能是继承 tableView 并覆盖setContentOffsetcontentOffset 必须在某个点设置为 0 才能发生跳转。在名为isUpdatingCellHeight 的tableview 中添加一个bool 属性,并且只有当这个变量是NO 时才会真正更新_contentOffset。因此,在更新表格之前将其设置为YES,然后将其设置为NO,然后如上所述设置contentOffset
  • 你第一个使用动画取消技巧的方法让它起作用了。我认为它比子类化更优雅一点。我不想限制它正常的单元格高度调整操作,只是在这种情况下需要反转它。
【解决方案4】:

更简化的解决方案(在 textView 更改时添加通知观察者),Swift 版本。主要技巧是使用UIView.setAnimationsEnabled

func textViewDidChanged(notification: NSNotification) {
    UIView.setAnimationsEnabled(false)

    let contentOffset = self.tableView.contentOffset

    tableView.beginUpdates()
    tableView.endUpdates()

    tableView.contentOffset = contentOffset

    UIView.setAnimationsEnabled(true)
}

【讨论】:

  • 有趣,我不知道这种方法存在。谢谢!
  • @Jadar,谢谢,如果该方法有效并且原始解决方案更简单,请将其标记为答案。如果它对您有帮助,您至少可以为它投票,以便其他用户可以轻松找到它。
  • 我目前没有办法测试它,因为我不再使用这部分 UI。如果您有更多像当前接受的答案那样解释的 cmets,我会更倾向于这样做。
猜你喜欢
  • 1970-01-01
  • 2017-08-22
  • 1970-01-01
  • 1970-01-01
  • 2014-05-08
  • 1970-01-01
  • 1970-01-01
  • 2016-10-03
  • 1970-01-01
相关资源
最近更新 更多