Изменять размер UITableViewCell асинхронно и сгенерировать UIView-Encapsulated-Layout-Height
Я пытаюсь изменить размер ячейки представления таблицы "изнутри", используя 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;
(это вариант, когда веб-просмотр содержится в другом представлении и этот вид соответственно изменяется).
Поскольку весь процесс автоматического макетирования завершается, когда это происходит, я устанавливаю
[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, я не могу переопределить ограничение, созданное табличным представлением.
Что расстраивает:
Если я заменю веб-представление простой многострочной меткой и знаю все размеры во время первой компоновки ячеек, все работает отлично. Это асинхронный характер системы загрузки веб-представлений, которая заставляет меня изменить макет после того, как ячейка отображается в первый раз.
Теперь мой вопрос:
Есть ли способ обойти это? Я действительно не хочу перезагружать камеру. Если ячейка является единственной на экране, она не используется повторно, и все начинается снова.
Возможно ли это, или архитектура UITableView зависит от этого внешнего ограничения, чтобы сделать его правильно?
Просто для удовольствия, я установил
self.translatesAutoresizingMaskIntoConstraints = NO;
в самой ячейке, в результате чего ячейка имеет размер 0,0 и ограничение:
"<NSLayoutConstraint:0x7f88506663a0 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7f8850648400(0)]>"
но он все еще там...
спасибо за вашу помощь.
Кстати: я уже прочитал все, что касается этого вопроса, в том числе:
Использование автоматической компоновки в UITableView для динамических раскладок ячеек и высоты строк в строке
Ответы
Ответ 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
Здесь a 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