iOS - UITableView 不滚动到数据源中的最后一行
iOS - UITableView Does Not Scroll To Last Row In Data Source
我正在开发 iOS 应用程序的消息传递组件。每条消息在我的 UITableView _messageTable
上都是一行 我在 viewDidLoad
、viewWillAppear
和 viewDidAppear
中尝试了以下代码(消息来自后台线程):
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];
}
我正在开发 iOS 应用程序的消息传递组件。每条消息在我的 UITableView _messageTable
上都是一行 我在 viewDidLoad
、viewWillAppear
和 viewDidAppear
中尝试了以下代码(消息来自后台线程):
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];
}