我正在使用iOS 8新的自我调整单元格。在视觉上它运作良好 - 每个单元格大小合适。但是,如果我尝试滚动到最后一行,则表格视图似乎不知道其正确的大小。这是一个错误还是有解决方法?
使用此项目 - TableViewCellWithAutoLayoutiOS8(引自this SO answer),我按预期获得了自动调整大小的单元格。
但是,如果我正在调用 scrollToRowAtIndexPath 函数,如下所示:
tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: model.dataArray.count - 1, inSection: 0), atScrollPosition: .Bottom, animated: true)
我没有到达最后一排 - 它只让我到了中途。
即使试图使用这样的低级功能:
tableView.setContentOffset(CGPointMake(0, tableView.contentSize.height - tableView.frame.size.height), animated: true)
结果并不像预期的那样,它不会走到尽头。如果我点击很多次或等待片刻,最终它会到达正确的位置。似乎tableView.contentSize.height设置不正确,因此iOS"不知道"最后一个单元格在哪里。
感谢任何帮助。
由于
答案 0 :(得分:32)
更新:2015年6月24日
Apple已经解决了iOS 9.0 SDK中的大部分漏洞问题。从iOS 9 beta 2开始,所有这些问题都得到了修复,包括滚动到顶部&没有动画的表视图的底部,并在表视图的中间滚动时调用reloadData
。
以下是尚未解决的剩余问题:
已针对与动画滚动相关的问题提交了新的错误报告(rdar:// 21539211)。
原始答案
这是一个带有表视图行高估计的Apple bug,它已经存在,因为这个功能首先在iOS 7中引入。我直接与Apple UIKit工程师和开发人员福音传教士就此问题进行过工作 - 他们已经承认这是一个错误,但没有任何可靠的解决方法(没有禁用行高估计),并且似乎没有特别感兴趣修复它。
请注意,错误会以其他方式显示,例如当您在部分或完全向下滚动时调用reloadData
时消失表视图单元格(例如contentOffset.y
显着大于0)。
显然,对于iOS 8自定义单元格,行高估计至关重要,因此Apple确实需要尽快解决这个问题。
我于2013年10月21日以Radar#15283329的身份提交了此问题。 请提交重复的错误报告,以便Apple优先处理修复。
您可以附加这个简单的sample project来证明问题。它直接基于Apple自己的示例代码。
答案 1 :(得分: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)
})
请告诉我这是否也适合你。
答案 2 :(得分: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)
})
}
答案 3 :(得分:4)
我找到了一个临时的解决方法,可能会有所帮助,直到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;
}
这并不完美,但它为我完成了这项工作。现在我可以致电:
- (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];
}
}
在viewDidLayoutSubviews
上,它会在底部找到正确的位置(或非常接近的估计位置)。
我希望有所帮助。
答案 4 :(得分:1)
对于我的情况,我发现了一个临时的解决方法,没有建议计划的估计单元格高度。我通过在我的代码中注释掉以下方法来做到这一点:
- (CGFloat) tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
但是,请注意,如果您的单元格相互之间的差异很大,那么这样做可能会影响用户滚动时的用户体验。就我而言,到目前为止没有明显的差异。
希望它有所帮助!
答案 5 :(得分:1)
我在Swift 5 iOS 13中遇到了这个问题,这解决了我的问题
DispatchQueue.main.async { [weak self] in
self?.tableView.reloadData()
self?.tableView.scrollToRow(at: indexPath, at: .middle, animated: false)
}
答案 6 :(得分:0)
我的解决方案是使用故事板的大小作为估算。
所以不要这样:
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
我做了类似的事情:
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
MyMessageType messageType = [self messageTypeForRowAtIndexPath:indexPath];
switch (messageType) {
case MyMessageTypeText:
return 45;
break;
case MyMessageTypeMaybeWithSomeMediaOrSomethingBiggerThanJustText:
return 96;
break;
default:
break;
}
}
我正在编写一个聊天表视图,因此很可能我的许多单元格,特别是文本类型将大于IB中的单元格,特别是如果聊天消息很长。这似乎是一个相当不错的......好吧......估计并滚动到底部变得非常接近。随着滚动越来越长,它似乎稍微差一点,但我认为这是可以预期的
答案 7 :(得分:0)
在viewDidAppear可以解决问题后调用tableview reloadData
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.tableView reloadData];
}
答案 8 :(得分:0)
在故事板窗口中单击空白区域以取消选择所有视图,然后单击其中包含表格视图的视图,然后单击Resolve Auto Layout Issue
图标并选择Reset to Suggested Constraints
答案 9 :(得分:0)
虽然作为smileyborg's answer它是iOS 8.x中的错误,但它应该在您支持的所有平台中修复...
要解决iOS9之前的问题,下面的代码可以在没有任何dispatch_async或dispatch_after的情况下执行此操作。 在iOS 8.4模拟器上测试。
UPDATE :当滚动UIPageViewController使视图控制器可见时,调用(仅)layoutIfNeeded不起作用。所以请改用layoutSubviews(或者setNeedsLayout + layoutIfNeeded)。
// For iOS 8 bug workaround.
// See https://stackoverflow.com/a/33515872/1474113
- (void)scrollToBottomForPreiOS9
{
CGFloat originalY, scrolledY;
do {
// Lay out visible cells immediately for current contentOffset.
// NOTE: layoutIfNeeded does not work when hosting UIPageViewController is dragged.
[self.tableView layoutSubviews];
originalY = self.tableView.contentOffset.y;
[self scrollToBottom]; // Call -scrollToRowAtIndexPath as usual.
scrolledY = self.tableView.contentOffset.y;
} while (scrolledY > originalY);
}
答案 10 :(得分:0)
在创建具有不同高度的单元格的聊天tableView时,我遇到了同样的问题。我在viewDidAppear()生命周期方法中调用下面的代码:
// First figure out how many sections there are
let lastSectionIndex = self.tableView.numberOfSections - 1
// Then grab the number of rows in the last section
let lastRowIndex = self.tableView.numberOfRowsInSection(lastSectionIndex) - 1
// Now just construct the index path
let pathToLastRow = NSIndexPath(forRow: lastRowIndex, inSection: lastSectionIndex)
// Make the last row visible
self.tableView.scrollToRowAtIndexPath(pathToLastRow, atScrollPosition: UITableViewScrollPosition.None, animated: true)
如果这对您有用,请告诉我。
答案 11 :(得分:-1)
使用此简单代码滚动底部
var rows:NSInteger=self.tableName.numberOfRowsInSection(0)
if(rows > 0)
{
let indexPath = NSIndexPath(forRow: rows-1, inSection: 0)
tableName.scrollToRowAtIndexPath(indexPath , atScrollPosition: UITableViewScrollPosition.Bottom, animated: true)
}
}