iOS - UITableView 不滚动到数据源中的最后一行

iOS - UITableView Does Not Scroll To Last Row In Data Source

我正在开发 iOS 应用程序的消息传递组件。每条消息在我的 UITableView _messageTable 上都是一行 我在 viewDidLoadviewWillAppearviewDidAppear 中尝试了以下代码(消息来自后台线程):

dispatch_async(dispatch_get_main_queue(), ^{
    [_messageTable reloadData];
});
dispatch_async(dispatch_get_main_queue(), ^{
    [self scrollToBottomOfTable];
});

-(void)scrollToBottomOfTable {
    NSInteger rowCount = [_messageTable numberOfRowsInSection:0];
    if (rowCount > 0) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow: rowCount-1 inSection: 0];
        [_messageTable scrollToRowAtIndexPath: indexPath atScrollPosition: UITableViewScrollPositionBottom animated: YES];
    }
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return _privateMessages.count;
}

这段代码一直有效,直到大约有 20 行左右。但是当有更多消息时,它不会一直滚动到底部。有某种限制吗?如果这意味着一直滚动到底部,我可以接受视图加载延迟。最终我会实现某种消息加载上限,但我想先了解并解决这个问题。

编辑

这是视图控制器中的 table 视图。我在 User 对象的数组 属性 中保存发送和接收的 Message 对象(消息对话另一端的人。app.hero 是登录的用户在,继承形式 User 对象)。没有意义的是代码可以完美地处理多达 20 条消息。除此之外,它不会一直滚动,但我仍然可以按预期手动滚动到底部。其余的单元格配置代码是:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
tableView.estimatedRowHeight = 20.0;
tableView.rowHeight = UITableViewAutomaticDimension;
Message *message = [_privateMessages objectAtIndex:indexPath.row];
static NSString *cellId = @"messageCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
    cell.textLabel.numberOfLines=0;
}
return [self configureTableCell:cell forMessage:message];
}

- (UITableViewCell *)configureTableCell:(UITableViewCell *)cell forMessage:(Message *)message {
AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
if (message.sender == app.hero) {
    cell.backgroundColor = [UIColor whiteColor];
    cell.textLabel.textAlignment = NSTextAlignmentRight;
} else {
    cell.backgroundColor = [UIColor colorWithRed:0 green:1 blue:0.2 alpha:0.3];
    cell.textLabel.backgroundColor = [UIColor colorWithWhite:0 alpha:0];
    cell.textLabel.textAlignment = NSTextAlignmentLeft;
}
cell.textLabel.text = message.content;
return cell;
}

我确定此问题与单元格高度有关。通过将 tableView.estimatedRowHeight 增加到 44.0,table 视图完美地滚动到底部。但是,当消息在给定单元格中换行超过 1 行时仍然存在问题。对于每条超过 1 行的消息,table 滚动条会短几个像素。完全删除 tableView.estimatedRowHeight 似乎会导致与将其设置为 44.0.0 类似的行为。我想说我原来的问题已经得到解答,但我仍然不确定如何让它完美滚动,因为可能存在多行单元格。

编辑 - 解决方案

滚动不正确的问题实际上是通过删除UITableViewAutomaticDimension并手动计算heightForRowAtIndexPath中的高度来解决的。

这是一个适用于自动调整单元格高度大小的解决方案。这是一个很好的解决方法,但这似乎是一个 Apple 错误。

viewDidLoad中设置_manualScrolling=NO

-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
    if (!decelerate) {
        _manualScrolling = NO;
    } else {
        _manualScrolling = YES;
    }
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    _manualScrolling = YES;
}

-(void)reloadTable {
    dispatch_async(dispatch_get_main_queue(), ^{
        [_messageTable reloadData];
    });
    dispatch_async(dispatch_get_main_queue(), ^{
        [self scrollToBottomOfTable];
    });
}

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (!_manualScrolling && ![self scrolledToBottom]) {
        [self scrollToBottomOfTable];
    }
}

-(BOOL)scrolledToBottom {
    NSInteger rowCount = [_messageTable numberOfRowsInSection:0];
    NSArray *visibleIndices = [_messageTable indexPathsForVisibleRows];
    NSIndexPath *lastVisibleIndex = [visibleIndices lastObject];
    NSIndexPath *lastIndex = [NSIndexPath indexPathForRow: rowCount-1 inSection: 0];
    return lastVisibleIndex.row == lastIndex.row;
}

-(void)scrollToBottomOfTable {
    NSInteger rowCount = [_messageTable numberOfRowsInSection:0];
    if (!rowCount > 0) return;
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow: rowCount-1 inSection: 0];
        [_messageTable scrollToRowAtIndexPath: indexPath atScrollPosition: UITableViewScrollPositionBottom animated: YES];
}