我正在尝试使用 iOS 8 "从内部"调整表格视图单元格的大小,因此没有实现
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
但使用:
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 200;
单元格具有从上到下的约束。
该单元格包含(除其他事项外)一个 UIWebview,该视图在加载后通过询问滚动视图的高度来异步了解其大小:
CGFloat fittingHeight = self.messageTextWebView.scrollView.contentSize.height;
(这是一种变体,其中 Web 视图包含在另一个视图中,并且该视图相应地调整大小)。
因为发生这种情况时整个自动布局过程已经完成,所以我设置
[self setNeedsUpdateConstraints];
在单元格中的视图中,该视图冒泡到单元格并再次向下冒泡layoutSubviews
.
最后,我得到了可怕的Unable to simultaneously satisfy constraints.
.打破一切的约束是
"<NSLayoutConstraint:0x7f8c29d157f0 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7f8c2b063eb0(270)]>"
此约束由表视图在首次计算单元格时创建。
它杀死了我自己:
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7fa8a8515b70 V:[UIView:0x7fa8aa0263e0(263)]>
尽管我将约束的优先级设置为 1000,并将抗压性设置为 1000,但我无法覆盖表视图创建的约束。
令人沮丧的是:如果我用简单的多行标签替换 Web 视图并在第一个单元格布局期间知道所有大小,则一切正常。正是 Web 视图加载系统的异步性质迫使我在第一次渲染单元格后更改布局。
现在我的问题:
有什么办法吗?我真的不想重新加载单元格。如果单元格是屏幕上唯一的单元格,则不会重复使用它,整个事情会重新开始。这是否可能,或者 UITableView 体系结构是否依赖于外部约束来正确呈现自身?
只是为了好玩,我设定
self.translatesAutoresizingMaskIntoConstraints = NO;
,导致单元格大小为 0,0 且约束:
"<NSLayoutConstraint:0x7f88506663a0 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7f8850648400(0)]>"
但它仍然在那里...
感谢您的帮助。
顺便说一句:我已经阅读了有关此事的所有内容,包括:在UITableView中使用自动布局进行动态单元格布局和可变行高
这是一个UITableViewCell
子类,它管理UIWebView
并正确调整其高度以使用UITableViewAutomaticDimension
UITableView
。
主要是保持UIWebView
高度的NSLayoutConstraint
。 在更新约束中更新其常量。 告诉父表视图在发生更改时重新计算单元格高度。
@implementation WebTableViewCell
{
IBOutlet UIWebView* _webview; // glued to cell content view using edge constraints
IBOutlet NSLayoutConstraint* _heightConstraint; // height constraint for the webview itself
}
- (void) awakeFromNib
{
_webview.scrollView.scrollEnabled = NO;
// use this to test various document heights
// [_webview loadHTMLString: @"<html><body style='height:100px;'>Hello, World</body></html>" baseURL: nil];
// or, a real web page
[_webview loadRequest: [NSURLRequest requestWithURL: [NSURL URLWithString: @"http://stackoverflow.com/users/291788/tomswift"]]];
}
- (void) updateConstraints
{
[super updateConstraints];
// get the document height.
CGFloat height = [[_webview stringByEvaluatingJavaScriptFromString: @"document.height"] floatValue];
if ( _heightConstraint.constant != height )
{
// update
_heightConstraint.constant = height;
// ask the tableview to recalc heights
dispatch_async(dispatch_get_main_queue(), ^{
UITableView* tableView = (UITableView*)self.superview;
while ( tableView != nil && ![tableView isKindOfClass: [UITableView class]] )
tableView = (UITableView*)tableView.superview;
[tableView beginUpdates];
[tableView endUpdates];
});
}
}
- (void) webViewDidFinishLoad:(UIWebView *)webView
{
[self setNeedsUpdateConstraints];
}
@end
经过更多的研究,我的结论是:
要么使用现在允许 HTML 内容的属性字符串(从 iOS7 开始):
[[NSAttributedString alloc] initWithData:[message dataUsingEncoding:NSUTF8StringEncoding]
options:
@{
NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: [NSNumber numberWithInt:NSUTF8StringEncoding]
}
documentAttributes:nil error:&err];
HTML解析器还可以,限制是
- 切勿使用 SRC 标记引用网络上的内容。内容加载到主线程上。我认为他们必须这样做才能强制同步渲染。
- 没有互动(这实际上是一件好事)。
或:集合视图可能有效,但我尚未转换表视图 - 根据我对 NSAttributedString 的测试结果,我可能会跳过它......
更新
我尝试使用梦幻般的 https://github.com/TTTAttributedLabel/TTTAttributedLabel它呈现属性字符串,并具有检测链接的额外好处。这就是我需要的一切——几乎。它不会呈现标签...
回到UITextView,令人惊讶的是工作得很好。