异步调整UITableViewCell与生成的UIView-Encapsulated-Layout-Height

时间:2014-11-16 14:15:49

标签: ios uitableview ios8 autolayout constraints

我正在尝试使用iOS 8“从内部”调整表格视图单元格,因此实现

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;

但使用:

self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 200;

单元格从上到下有限制。

单元格包含(除其他外)一个UIWebview,它通过询问scrollview的高度来加载后异步地知道它的大小:

CGFloat fittingHeight = self.messageTextWebView.scrollView.contentSize.height;

(这是一种变体,其中webview包含在另一个视图中,并且该视图会相应地调整大小)。

因为当发生这种情况时整个自动布局过程完成,我设置

[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)]>"

但它仍然存在......

感谢您的帮助。

顺便说一句:我已经阅读了有关此事的所有内容,包括: Using Auto Layout in UITableView for dynamic cell layouts & variable row heights

2 个答案:

答案 0 :(得分:3)

这是一个UITableViewCell子类,用于管理UIWebView并正确调整其高度,以使UITableView集合使用UITableViewAutomaticDimension

主要是为NSLayoutConstraint身高维持UIWebView。在updateConstraints中更新其常量。当有变化时,告诉父表视图重新计算单元格高度。

@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

答案 1 :(得分:1)

经过一些研究后,我的结论是:

使用现在允许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,令人惊讶地工作正常。