iOS 8自动单元格高度 - 无法滚动到最后一行

Ben*_*enB 57 uitableview ios swift ios8

我正在使用iOS 8新的自动调整单元格.在视觉上它运作良好 - 每个单元格大小合适.但是,如果我尝试滚动到最后一行,表视图似乎不知道它的正确大小.这是一个错误还是有解决方法?

以下是重建问题的方法:

使用这个项目 - TableViewCellWithAutoLayoutiOS8(从这个SO答案引用),我按预期得到了自动调整大小的单元格.

但是,如果我调用scrollToRowAtIndexPath函数,如下所示:

tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: model.dataArray.count - 1, inSection: 0), atScrollPosition: .Bottom, animated: true)
Run Code Online (Sandbox Code Playgroud)

没有到达最后一排 - 它只让我到了中途.

即使试图使用这样的低级函数:

tableView.setContentOffset(CGPointMake(0, tableView.contentSize.height - tableView.frame.size.height), animated: true)
Run Code Online (Sandbox Code Playgroud)

结果不如预期,它不会达到目的.如果我点击很多次或等待片刻,最终它会到达正确的位置.似乎tableView.contentSize.height设置不正确,因此iOS"不知道"最后一个单元格在哪里.

非常感谢任何帮助.

谢谢

smi*_*org 32

更新:2015年6月24日

从iOS 9.0 SDK开始,Apple已经解决了大部分漏洞.从iOS 9 beta 2开始修复所有问题,包括滚动到没有动画的表格视图的顶部和底部,以及在表格视图reloadData中间滚动时调用.

以下是尚未修复的剩余问题:

  1. 使用较大的估计行高时,使用动画滚动到最后一行会导致表视图单元格消失.
  2. 当使用较小的估计行高时,使用动画滚动到最后一行会导致表视图过早地完成滚动,从而在可见区域下方留下一些单元格(并且最后一行仍然在屏幕外).

已经针对与动画滚动相关的这些问题提交了新的错误报告(rdar:// 21539211).

原始答案

这是一个带有表视图行高估计的Apple bug,它已经存在,因为这个功能首先在iOS 7中引入.我已经直接与Apple UIKit工程师和开发人员福音传教士就此问题进行过工作 - 他们已经承认它是一个错误,但没有任何可靠的解决方法(没有禁用行高估计),并没有特别感兴趣修复它.

请注意,错误以其他方式表现出来,例如当您reloadData在部分或完全向下滚动时调用时消失的表视图单元格(例如contentOffset.y,显着大于0).

显然,对于iOS 8自定义单元格,行高估计非常重要,因此Apple确实需要尽快解决这个问题.

我于2013年10月21日以Radar#15283329的身份提交了此问题.请提交重复的错误报告,以便Apple优先处理修复.

您可以附加此简单示例项目来演示该问题.它直接基于Apple自己的示例代码.

  • @abinop Slack的文本视图控制器如何为UITableView提供一般案例替换/解决方法?我认为这仅适用于某些特定用例,当然不值得重新实现现有代码. (2认同)

abi*_*nop 20

这是一个非常烦人的错误,但我认为我找到了一个永久的解决方案,但我无法完全解释原因.

在一小段(未被注意到的)延迟后调用该函数:

let delay = 0.1 * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))

dispatch_after(time, dispatch_get_main_queue(), {
  tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: model.dataArray.count - 1, inSection: 0), atScrollPosition: .Bottom, animated: true)
})
Run Code Online (Sandbox Code Playgroud)

请告诉我这是否适合你.

  • 这对我来说似乎没有用,即使有更长的时间延迟.=( (6认同)

小智 13

这绝对是Apple的一个错误.我也有这个问题.我通过调用"scrollToRowAtIndexPath"方法解决了这个问题,两个示例代码是:

        if array.count > 0 {
        let indexPath: NSIndexPath = NSIndexPath(forRow: array.count - 1, inSection: 0)
        self.tblView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Bottom, animated: true)
        let delay = 0.1 * Double(NSEC_PER_SEC)
        let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))

        dispatch_after(time, dispatch_get_main_queue(), {
            self.tblView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Bottom, animated: true)
        })
    }
Run Code Online (Sandbox Code Playgroud)

  • iOS9对我有用,谢谢!我稍微修改它以使用`dispatch_async(dispatch_get_main_queue()...`而不是那样,没有可确定的延迟,它就在主队列空闲时. (3认同)

Gui*_*ura 5

我找到了一个临时解决方法,它可能会有所帮助,直到 Apple 决定修复困扰我们的许多错误。

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *text = [self findTextForIndexPath:indexPath];
    UIFont *font = [UIFont fontWithName:@"HelveticaNeue" size:13];
    CGRect estimatedHeight = [text boundingRectWithSize:CGSizeMake(215, MAXFLOAT)
                                                options:NSStringDrawingUsesLineFragmentOrigin
                                             attributes:@{NSFontAttributeName: font}
                                                context:nil];
    return TOP_PADDING + CGRectGetHeight(estimatedHeight) + BOTTOM_PADDING;
}
Run Code Online (Sandbox Code Playgroud)

这并不完美,但它为我完成了工作。现在我可以调用:

- (void)scrollToLastestSeenMessageAnimated:(BOOL)animated
{
    NSInteger count = [self tableView:self.tableView numberOfRowsInSection:0];
    if (count > 0) {
        NSInteger lastPos = MAX(0, count-1);
        [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForItem:lastPos inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:animated];
    }
}
Run Code Online (Sandbox Code Playgroud)

On viewDidLayoutSubviews,它会在底部找到正确的位置(或非常接近的估计位置)。

我希望这有帮助。