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

问题描述:

我正在研究iOS应用程序的消息传递组件。每个消息是一排我UITableView _messageTable我尝试下面的代码在viewDidLoadviewWillAppearviewDidAppear(消息从后台线程进来):iOS - UITableView不滚动到数据源中的最后一行

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行左右。但是当有更多的消息时,它不会完全滚动到底部。是否有某种限制?如果它意味着一直滚动到底部,那么我认为视图加载延迟是可以的。最终我会实现某种消息加载上限,但我想先理解并解决此问题。

编辑

这是视图控制器内的表视图。我正在保存已发送并接收Message对象的User对象的数组属性(消息对话另一端的人。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; 
} 
+0

我没有看到你目前的作品有任何问题。你能否包含更多的代码,特别是如何更新'_privateMessages'?这可能是一个多线程问题。 – Armin 2015-01-26 20:33:40

+0

这是一个表视图控制器或具有表视图的视图控制器吗?如果是后者,确保桌面视图不在屏幕的底部。 – rmaddy 2015-01-26 20:36:29

+1

你是否动态地设置细胞的高度? – 2015-01-26 20:38:11

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

编辑 - 解

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

+0

我记得我遇到过这种情况,需要仔细检查以确保电池本身和要求它的接口之间的行高一致。 – 2015-01-26 22:01:26

+0

(你可能想要做的是将单元格高度存储在你的dataSource中,这样你就可以始终在'heightForRow ...'中返回一个精确的值。) – 2015-01-26 22:14:14

+0

(并且一定要实现'heightForRow'.IIRC,如果你的单元格不是全部标准高度,你需要这样做。) – 2015-01-27 01:47:04

这是一个可以很好地处理自动单元高度尺寸的解决方案。这是一个很好的解决方法,但这似乎是Apple的一个漏洞。

设置_manualScrolling=NOviewDidLoad

-(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]; 
}