【问题标题】:Resize UITableViewCell asynchronously vs. generated UIView-Encapsulated-Layout-Height异步调整 UITableViewCell 大小与生成的 UIView-Encapsulated-Layout-Height
【发布时间】:2015-01-13 11:47:52
【问题描述】:

我正在尝试使用 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;

(这是一种变体,其中 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

【问题讨论】:

  • 单元格上是否设置了 autoresizesSubviews?这意味着视图的父级将设置其大小,而不是扩展视图以适应其子级。 (虽然......我从来没有在 tableView 上下文中测试过......)
  • 是的。它同时设置在单元格和单元格的内容视图上。
  • 你试过关掉它吗?也许您看到的系统添加的约束来自该设置。
  • 同样的事情。不影响生成的约束。

标签: ios uitableview ios8 autolayout constraints


【解决方案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 出乎意料地工作得很好。

【讨论】:

    【解决方案2】:

    这是一个 UITableViewCell 子类,它管理 UIWebView 并为 UITableView 设置正确调整其高度以使用 UITableViewAutomaticDimension

    主要是为UIWebView 高度保持NSLayoutConstraint。在 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
    

    【讨论】:

    • 这正是我尝试的,减去将开始/结束更新包装在异步调度中。但无济于事 - 我仍然会尝试通过打破约束来恢复...由于自动 UIView-Encapsulated-Layout-Height
    • 我没有这个问题(但我知道你指的是什么)。您正在运行什么设备/操作系统级别?我的是iOS8.1手机模拟器。
    • 8.1 模拟。不过,在设备上也是如此。
    猜你喜欢
    • 1970-01-01
    • 2021-09-01
    • 2015-04-09
    • 2015-10-09
    • 2016-03-04
    • 2021-05-21
    • 2017-02-01
    • 2015-11-18
    • 1970-01-01
    相关资源
    最近更新 更多