我有一个使用UITableViewCell
和Autolayout
的自定义iOS8 Dynamic Height
,其中包含两个不同大小的标签。上面的标签可以是 1到2行的任何地方,底部标签总是只有1行。
在:cellForRowAtIndexPath:
中,我将上部标签的文本设置为“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]
中调用viewWillAppear:
,因此如果错误地呈现某些内容,只需打开另一个视图并返回此处就可以解决问题。将手机转到另一侧,然后再回到原件。
这是一张图片,解释了会发生什么(注意:两个单元格应该像第二个单元格一样):
以下是我使用UITableViewCell
在StoryBoard
中设置AutoLayout
的方式:
我没有更改任何属性(例如拥抱和压缩优先级)。
有没有人能指引我正确的方向/让我知道我做错了什么?
编辑1:这是一张照片,显示了不同的UILabel
Frames
对于(1)正确的布局(2)错误的布局(3)布局时的布局单元格正在等待它的最终文本(导致错误的布局发生)
编辑2:从块中调用[strongCell setNeedsLayout]
和[strongCell layoutIfNeeded]
并不能解决我的问题,但会导致此AutoLayout
错误出现在控制台中。你能帮我调试吗?
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.
答案 0 :(得分:1)
为了再次布置单元格,您需要使用reload
方法reload
单元格。
你可以通过这种方式实现......
首先,创建一个可变字典属性来存储单元格的文本......
@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];
}
}];
....
}
第一次通过此操作会触发字符串的异步提取。完成后,它将其存储在本地,然后重新加载该行。
第二次通过它将获得本地存储的字符串并使用它而无需再次下载。
答案 1 :(得分:0)
如果您使用多行UILabel,请不要忘记需要正确设置preferredMaxLayoutWidth。
尝试设置上标签的preferredMaxLayoutWidth
:
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];
}];
再次编辑:
我强烈建议您在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];
}
}];