Ios 文本更改时,自动布局动态高度表视图单元格呈现错误
我有一个自定义的Ios 文本更改时,自动布局动态高度表视图单元格呈现错误,ios,objective-c,uitableview,autolayout,Ios,Objective C,Uitableview,Autolayout,我有一个自定义的UITableViewCell,它使用Autolayout和iOS8动态高度,包含两个不同大小的标签。上标签可以是1到2行之间的任意位置,而下标签始终只有1行 在:cellforrowatinexpath:中,我将上部标签的文本设置为“Loading..”,并调用一个方法从服务器(或缓存)(可以是任意长度)检索实际文本。第二个标签设置为其最终文本 ... cell.title.text = @"Loading..."; cell.subtitle.text = source.na
UITableViewCell
,它使用Autolayout
和iOS8动态高度
,包含两个不同大小的标签。上标签可以是1到2行之间的任意位置,而下标签始终只有1行
在:cellforrowatinexpath:
中,我将上部标签的文本设置为“Loading..”,并调用一个方法从服务器(或缓存)(可以是任意长度)检索实际文本。第二个标签设置为其最终文本
...
cell.title.text = @"Loading...";
cell.subtitle.text = source.name;
__weak NewsTableViewCell *weakCell = cell;
[[NewsManager sharedManager] getNewsForSource:source withBlock:^(NewsObject *object, NSError *error) {
NewsTableViewCell *strongCell = weakCell;
strongCell.title.text = object.articleHeadline;
}];
...
当该方法返回并将文本从“加载…”更改为实际文本时,会发生以下三种情况之一:
视图中调用[self.tableView reloadData]
将显示:
,因此,如果某些内容呈现错误,只需打开另一个视图并返回该视图即可解决问题。把手机转到另一边,然后又回到原来的样子也是如此
下面的图片解释了发生的情况(注意:两个单元格应与第二个单元格相似):
以下是我如何使用自动布局在故事板中设置UITableViewCell
:
我没有改变任何属性(如拥抱和压缩优先级)
谁能给我指点正确的方向/让我知道我做错了什么
编辑1:这是一张照片,显示了不同的ui标签
框架
(1)正确的布局(2)错误的布局(3)单元格等待最终文本时的布局(导致出现错误的布局)
编辑2:从块中调用[strongCell setNeedsLayout]
和[strongCell layoutifneed]
并不能解决我的问题,但会导致控制台中出现此自动布局
错误。你能帮我调试一下吗
Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you
don't want. Try this: (1) look at each constraint and try to figure out which
you don't expect; (2) find the code that added the unwanted constraint or
constraints and fix it. (Note: If you're seeing
NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the
documentation for the UIView property
translatesAutoresizingMaskIntoConstraints)
(
"<NSLayoutConstraint:0x1700927a0 UILabel:0x127d39c20'Horrifying moment lioness...'.top == UITableViewCellContentView:0x127d2e510.topMargin>",
"<NSLayoutConstraint:0x170092930 V:[UILabel:0x127d39c20'Horrifying moment lioness...']-(8)-[UILabel:0x127d39dd0'Daily Mail Online']>",
"<NSLayoutConstraint:0x170092a70 UILabel:0x127d39dd0'Daily Mail Online'.bottom == UITableViewCellContentView:0x127d2e510.bottomMargin>",
"<NSLayoutConstraint:0x170092c00 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x127d2e510(0)]>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x170092930 V:[UILabel:0x127d39c20'Horrifying moment lioness...']-(8)-[UILabel:0x127d39dd0'Daily Mail Online']>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
无法同时满足约束。
可能以下列表中至少有一个约束是您需要的约束
我不想要。尝试以下方法:(1)查看每个约束,并尝试找出哪一个约束
你不期待;(2) 查找添加不需要的约束的代码或
约束并修复它。(注意:如果您看到
如果您不了解NSAutoresizingMaskLayoutConstraints,请参阅
UIView属性的文档
翻译自动调整大小(从皮肤到肌肉)
(
"",
"",
"",
""
)
将尝试通过打破约束进行恢复
在UIViewAlertForUnsatifiableConstraints处创建一个符号断点,以便在调试器中捕获该断点。
中列出的UIView上UIConstraintBasedLayoutDebugging类别中的方法也可能会有所帮助。
如果使用多行UILabels,请不要忘记需要正确设置preferredMaxLayoutWidth
尝试设置上部标签的首选MaxLayoutWidth
:
cell.title.preferredMaxLayoutWidth = cell.title.bounds.size.width;
编辑:
__weak NewsTableViewCell *weakCell = cell;
[[NewsManager sharedManager] getNewsForSource:source withBlock:^(NewsObject *object, NSError *error) {
NewsTableViewCell *strongCell = weakCell;
strongCell.title.text = object.articleHeadline;
[strongCell setNeedsLayout];
[strongCell layoutIfNeeded];
}];
再次编辑:
__weak NewsTableViewCell *weakCell = cell;
[[NewsManager sharedManager] getNewsForSource:source withBlock:^(NewsObject *object, NSError *error) {
NewsTableViewCell *strongCell = weakCell;
strongCell.title.text = object.articleHeadline;
[strongCell setNeedsLayout];
[strongCell layoutIfNeeded];
}];
我强烈建议您在viewDidLoad
中检索数据。表视图重复使用单元格。当一个单元格滚动到屏幕外时,它将被添加到队列中,并将被重新用于屏幕上滚动的下一个单元格
如果您在cellForRow
中请求数据,则必须按如下方式检查单元格:
NSInteger row = indexPath.row;
[[NewsManager sharedManager] getNewsForSource:source withBlock:^(NewsObject *object, NSError *error) {
// Update the datasource, e.g. caching the news in getNewsForSource:withBlock:
UITableViewCell *dangerousCell = [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:0]];
if (dangerousCell != nil) {
NSString *articleHeadline = object.articleHeadline;
if ([dangerousCell.title.text isEqualToString:articleHeadline]) {
return;
}
textLabel.text = articleHeadline;
[tableView reloadData];
}
}];
为了重新布置单元,需要使用重新加载
方法重新加载
单元
你可以通过这种方式实现它
首先,创建一个可变字典属性来存储单元格的文本
@property (nonatomic, strong) NSMutableDictionary *textDictionary;
然后在某个地方初始化它
然后在第行的单元格中
更新了以下评论
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
...
cell.subtitle.text = source.name;
// get the text from the dictionary
NSString *titleText = self.textDictionary[source];
if (titleText) {
// second time through the text exists so just use it.
cell.title.text = titleText;
} else {
// first time through the text is nil so set it to default and download it.
cell.title.text = @"Loading...";
// this just stops the download starting again before it has completed
self.textDictionary[source] = @"Loading...";
}
// recheck the text and reload if it has changed
[[NewsManager sharedManager] getNewsForSource:source withBlock:^(NewsObject *object, NSError *error) {
NSString *oldText = self.textDictionary[source];
NSString *newText = object.articleHeadline;
// reload if the text has changed
if (![oldText isEqualToString:newText]) {
// store the text in the dictionary
self.textDictionary[source] = newText;
// reload the indexPath (will only trigger if the cell is visible)
[tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
}];
....
}
第一次通过它触发字符串的异步获取。完成后,将其存储在本地,然后重新加载行
第二次使用时,只需获取本地存储的字符串并使用该字符串,而无需再次下载。我尝试在传递的块和cellforrowatinexpath:
中添加该行,但这似乎并没有使它变得更好。实际上,现在它似乎总是会导致第二个标签消失,而第一个标签仅为一行,不管文本长度如何,直到您再次调用重新加载数据
。在更改文本时,我尝试调用[strongCell layoutSubview]
和[strongCell layoutNeeded]
,但这也不起作用。这一切真的不应该自动完成吗?我的意思是,我认为我已经正确设置了约束条件,所以我不知道为什么textlabel不能适应内容,为什么第二个textlabel会消失,为什么单元格不能增长以容纳较大的文本在主线程中调用getNewsForSource
的块
?getNewsForSource:
检查对象是否在缓存中。如果它在缓存中,则从主线程调用块()
,如果不是,则从等待网络连接的后台线程调用。那有关系吗?我知道你不能从背景线程对布局进行更改,但是更改文本是有效的,所以我不明白为什么布局不能正确渲染。也看到了原来的帖子,我添加了另一张图片。我认为当请求完成时,你必须更新单元格的高度。当文本加载时,你的处理方式不正确。您当前正在做的是更改文本,并假设布局将为您固定。当您获得新文本时,需要重新加载该单元格。这将重新布局cell.Los,将下载的文本存储在数组中,以便在cell for row中,您可以检查数组并将标题设置为“加载…”(如果不可用),或将数组中的文本设置为“加载…”(如果不可用)