ios - Autolayout 动态高度 TableView 单元格在文本更改时呈现错误

标签 ios objective-c uitableview autolayout

我有一个使用 AutolayoutiOS8 Dynamic Height 的自定义 UITableViewCell,包含两个不同大小的标签。上面的标签可以是 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;
}];
...

当方法返回并将文本从“正在加载...”更改为实际文本时,会发生以下三种情况之一:

  1. 一切都正确呈现。
  2. 移除第二个标签并将第一个标签固定到一行。
  3. 第一个标签被截去一半宽度(这通常发生在将手机侧转并再次变回竖屏后)。

我在 viewWillAppear: 中调用了 [self.tableView reloadData],因此如果出现错误,只需打开另一个 View 并返回此 View 即可解决问题。将手机转到另一侧,然后再回到原来的位置也是如此。

这是一张解释发生了什么的图片(注意:两个单元格应该像第二个一样):

enter image description here

下面是我如何使用 AutoLayoutStoryBoard 中设置 UITableViewCell:

enter image description here enter image description here

我没有更改任何属性(例如拥抱和压缩优先级)。

谁能指导我正确的方向/让我知道我做错了什么?

编辑 1:这是一张照片,显示了 (1) 正确布局 (2) 错误布局 ( 3) 单元格等待它的最终文本时的布局(这会导致发生错误的布局)

enter image description here

编辑 2: 从 block 中调用 [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.

最佳答案

为了再次布局单元格,您需要使用 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];
        }
    }];

    ....
}

第一次通过这个触发字符串的异步获取。完成后,它会将其存储在本地,然后重新加载该行。

第二次通过它将只获取本地存储的字符串并使用它而无需再次下载。

关于ios - Autolayout 动态高度 TableView 单元格在文本更改时呈现错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30684220/

相关文章:

iPhone - 如何使用 TableView 单元格?

ios - 空 CGMutablePathRef 路径?

ios - 登录页面未完全注销用户 iOS

objective-c - 如何使用NSFileManager setAttributes递归更改目录的权限

ios - 自定义 TableViewCells 在静态和动态时显示不同

ios - 自定义 TableView 单元格重用代码审查问题

ios - 使用自动布局将 View 定位在 (c + (x * superview.width))

ios - cocos2d 和 TexturePacker : initWithSpriteFrame consuming 16 Mb of memory for a small file

iphone - 全景热点实现

ios - UITextView 不更新它的 contentSize