iOS 8:UITableViewCell的详细文本未正确更新

18

tl;dr: 在iOS中,数值变化时,我能否通过自动布局系统使detailTextLabel的大小得到更新?

自iOS 8以来,有人遇到过UITableViewCell中detailText标签的问题吗?

我的表格既有文本也有详细字符串。最初,详细文本为空字符串(@"")。在执行故事板segue转到编辑屏幕后,我返回一个新的详细文本值并将其更新。我尝试在viewWillAppear中重新加载表格,以便在返回到上一个视图时立即显示该值。

一旦表格视图再次可见,表格单元格已将文本字段向上移动以为详细文本腾出空间,但是没有显示详细文本。直到我返回到编辑屏幕并第二次返回时,文本才会显示。

我做了什么来解决问题:看起来详细文本标签的自动布局没有正确更新,而记录detailTextLabel框架的大小和组成则证实了这一点。

我可以通过在viewDidAppear中运行[table reloadData]来强制更新文本,但这会留下我不喜欢的闪烁效果,并且看起来不专业。

编辑:我还做了一些额外的事情:我还使用 [cell.detailTextLabel sizeToFit] 强制调整了 detailTextLabel 的大小。这会导致它显示出来,但在单元格中以奇怪的方式偏移。再次进入编辑页面后,detailTextLabel 会修正其位置。

我创建了一个简单的项目作为 github 存储库,以展示我正在处理的内容:

https://github.com/acidaris/ios8_table_issue

我正在使用的视图控制器的主要代码也如下所示。
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self.table reloadData]; 
}


- (NSInteger)tableView:(UITableView *)tableView
    numberOfRowsInSection:(NSInteger)section {
    return 1; 
}

- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {  
    UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"CellIdentifier"];
    
    cell.textLabel.text = @"This is a test";
    cell.detailTextLabel.text = self.value;
    
    CGRect frame = cell.detailTextLabel.frame;
    NSLog(@"detailTextLabel x=%f y=%f width=%f height=%f",
        frame.origin.x,frame.origin.y,frame.size.width,frame.size.height);
    return cell; 
}

这个单元格是在Storyboard中原型化的,因此由dequeueReusableCellWithIdentifier:选择的单元格始终被定义。此外,故事板中的单元格类型设置为副标题,并且如果定义了初始值,则会显示。
如果有人能帮我弄清楚这个问题,我将非常感激。
部分解决方案
如果您正在子类化UITableViewCell,可以在布局完成时修改detailTextLabel的框架。这就是我所做的,它似乎已经起作用了,但在6 Plus上,我得到了一个奇怪的细分线,位于textLabel和detailTextLabel之间。编辑:(我已经调整了这个问题)。我不喜欢这个解决方案,但到目前为止,这是我找到的最好的解决方案。它在呈现视图后不会更新,而且相对简单。正如我上面所说,我将继续寻找更好的解决方案。
- (void)layoutSubviews {
  [super layoutSubviews]; 
  CGRect textFrame = self.textLabel.frame;
  [self.detailTextLabel sizeToFit];

  CGFloat x = textFrame.origin.x;
  CGFloat y = textFrame.origin.y + textFrame.size.height;

  CGSize detailSize = self.detailTextLabel.frame.size;
  CGRect newFrame = CGRectMake(x, y, detailSize.width, detailSize.height);

  self.detailTextLabel.frame = newFrame;
}

我已更新我的Github项目以反映我的当前解决方案。编辑3:这并不完美,因为它对于真正的自动布局框架具有错误的值,但它暂时适用于我的用途。

编辑4:我已经更新了我的layoutSubviews函数,使其更加智能化。它将根据标签内的内容调整大小,并在与文本标签相关的x/y坐标中适当地定位标签。


1
请查看UITableViewCell的子标题不会更新 - Carl Lindberg
看看@acidaris为此付出的所有努力!非常感激。 - Thompson
8个回答

19

我也遇到了同样的问题。我的解决方案是在-tableView:cellFForRowAtIndexPath返回单元格之前调用[cell layoutSubviews]方法。这对我起作用了,我没有觉得需要在单元格子类中重写layoutSubviews方法。


1
感谢@pixbug!这对我也起作用,我在viewdidload方法中更新了一个单元格。我认为可以在更新detailTextLabel.text后立即调用layoutSubViews。code <pre><code> self.dueDate.detailTextLabel.text = [dateFormatter stringFromDate:self.movie.dueDate]; [self.dueDate layoutSubviews]; </code></pre> - Santhu
1
这应该是被采纳的解决方案,在我的情况下,我正在使用静态单元格的Storyboard,所以我没有-tableView:cellFForRowAtIndexPath。但在修改每个单元格的内容后调用[cell layoutSubviews]使单元格在视图加载后立即可见。 - Alex Su
2
勿直接调用layoutSubviews方法。如果您需要立即更新单元格的布局,请先调用setNeedsLayout,然后再调用layoutIfNeeded方法。 - jlukanta
6
调用 [cell layoutIfNeeded] 解决了我的问题,对我来说已经完美地起作用了。只有在需要强制布局时才需要调用 setNeedsLayout - Bill Weinman

8

我在使用故事板中的segue时,遇到了单元格未能正确更新的问题。

尝试过以下方法:

[setNeedsLayout] and [layoutIfNeeded]

关于视图和表格视图,但它不起作用。

[self.tableView reloadData] is in viewDidAppear, as it should.

然后我尝试了pixbug的建议,它起到了作用。但是不应该直接使用[layoutSubviews]。因此,我尝试了文件中建议的单元格而不是tableView或视图中的方法。
尝试过程中:
[cell setNeedsLayout] 

但这并没有起作用。
尝试过。
[cell layoutIfNeeded] 

这对我很有用。

在返回单元格之前,我将其放置在此处。


这也解决了我的问题(“UITableViewCell重用时为空白”http://stackoverflow.com/questions/31241249/uitableviewcell-blank-when-reused) - Jeff

2

我在一个未启用自动布局的iOS 8故事板中遇到了同样的问题。

我有一个带静态表格视图单元格的表格视图,底部是一个静态表格视图单元格。在IB中,我在该表格单元格的内容区域(样式:“右详细信息”)中添加了一些空格。然后在代码(ViewDidLoad)中,我更新了该单元格的内容...

self.copyrightsCell.detailTextLabel.text = @"<a string>";

在纵向模式下,如果没有IB空格,单元格将不可见。

但是,如果有初始空格,则单元格的内容随后会正确显示。

希望这能帮助到某些人。


1

我遇到了一个类似的问题,与静态 UITableView 相关。我更改了标签的文本,但除非我点击单元格或执行任何强制更新视图的操作,否则屏幕上不会更新它。我的解决方法是在更新文本后调用:

tableView.reloadData()

附言:这没有任何意义;因为这是一个静态表视图,我不知道为什么它会起作用,但它确实起作用了!


1
我有同样的问题。 我确定数据可用并已分配给cell.detailTextLabel.text。 我注意到一旦一个值被分配,如果该值在返回tableView时被更改,则不会闪烁。 因此,对我来说,只有在第一次将值分配给detailTextLabel时才存在问题。

是的,我仍然无法找到一个好的解决方案来解决这个问题。如果我在viewWillAppear和viewDidAppear期间执行reload,我可以让值出现,但它是在视图显示后设置的,所以该值为空,然后才被设置。(正如你所说,第一次显示时没问题)。 - acidaris
我可能有一个部分解决方案,请参见上面的编辑。虽然我不完全喜欢这个解决方案,但它确实按照我的要求更新了文本。 - acidaris
我发现当我滚动表格时,即使在viewDidAppear中强制加载detailTextLabel.text到单元格中,它也会被移除。 - iCyberPaul
你试过我在主问题正文中发布的修复方案了吗(在自定义UITableViewCell中重写layoutSubviews)?这不是完美的解决办法,但它会将标签的框架强制设置为适当的值。你可以进行一些实验来确定应该设置成什么值,我的应用只需要框架长度的一半,所以150.0对我来说就可以。 - acidaris
在这种情况下,我正在使用默认的UITableViewCell,所以我发现在尝试覆盖方法时会出现问题。 - iCyberPaul
1
这似乎是 https://dev59.com/ql8e5IYBdhLWcg3wZprw 的重复。解决方法是在标签中永远不要有非空文本(即使在故事板中也是如此),或者使用上述答案中的代码补丁,这是苹果错误的一个解决方案。 - Carl Lindberg

1

所以,我跟随了这个帖子和许多其他帖子。这个帖子引导我找到了似乎是正确答案的地方。我希望这能帮助其他人,因为自从iOS 7/8进行了某些更改以来,这让我疯狂。

我的答案是将正常处理代码放在viewWillAppear中,并添加这个[self.tableview layoutSubviews]而不是[self.tableView reload data]。我认为这与Apple在iOS 7/8中使事物更加可控有关。当我审查一些有关单元格如何工作的信息时,我想到了这个想法。

再次,我希望这可以帮助其他人解决这个令人恼火的问题。


0

我认为如果你需要reloadData,那就意味着在创建表格数据时它还没有被加载。

你只需要在viewdidload(或在表格视图获取数据之前的其他位置)中加载数据,然后相应地创建单元格即可。

通常,我只使用一个任何对象的数组,然后使用[array objectAtIndex:indexpath.row],这可能是你已经知道的。

另外,倒数第二段有一个未完成的句子,看起来很重要。


所以,如果我从viewWillAppear中删除[self.table reloadData],第一次加载是正确的,但更新不会发生。如果我将reloadData添加到viewDidLoad中,我会看到旧数据的闪烁,然后才是新数据。这似乎不太对。 - acidaris
更新了最后一段,并对我已经尝试过的事情进行了额外的编辑,以解决这个问题。 - acidaris

0

使用Xcode 6.3.2(6D2105)OS X Yosemite 10.10.3确认问题。 我确保正确的值被分配,但第一次没有显示,第二次才显示。 对我来说,cell.layoutSubviews()似乎是合理的,因为它似乎缺少刷新视图,添加layoutSubviews()就解决了问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接