今天我开始为iOS8准备好我的应用程序。
我发现我的UITableCells的字幕不会在viewWillAppear
内更新。
我把它归结为一个最小的例子:
我有一个带有2个单元格的静态单元格TableViewController(style = subtitle) 一个副标题为空,另一个副标题设置。
我像这样更新字幕:
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[self.without detailTextLabel] setText:@"foobar"];
[[self.with detailTextLabel] setText:@"barfoo"];
}
虽然Everythin在iOS7(以及6和5)下工作,但iOS8不会更新第一个单元格的标题。
但是,当我触摸单元格时,它会更新并显示文本。
这是模拟器问题吗?一个bug?我做错了吗?
答案 0 :(得分:47)
作为临时工作,我简单地在文本标签中引入了一个空格,并以编程方式将标签文本设置为nil,我将其设置为空格
cell.detailTextLabel.text = @" ";
相应地调整逻辑以处理单独的空白区域。
对于我来说,即使在加载viewcontroller之前我已经准备好了一个字符串,详细文本标签也没有显示出来。每当视图控制器出现时,我的许多单元格中的一个都会在详细文本标签中显示当前日期,但这也不起作用。
我认为这与iOS 8无法更新文本标签文本(如果最初设置为nil)的事实有关。
所以请注意,在界面构建器中也会在原型单元格中引入一个空格。我的自定义单元格的标签中的文字工作正常。
答案 1 :(得分:15)
Apple似乎添加了一个优化,当值为nil时,会从视图层次结构中删除detailTextLabel,并根据需要重新添加。不幸的是,在我的测试中,它会在布局过程中添加,但只有在之后它才会调整大小以适应布局过程中的新文本,因此大小仍为零。下一个布局传递(比如旋转)然后它将显示OK。
一种解决方法可能是在所有情况下强行将标签添加回视图层次结构(如果零大小,似乎应该没问题)。我有兴趣看看是否将以下类别放入您的应用中会修复问题。
#import <objc/runtime.h>
/*
* In iOS8 GM (and beta5, unsure about earlier), detail-type UITableViewCells (the
* ones which have a detailTextLabel) will remove that label from the view hierarchy if the
* text value is nil. It will get re-added during the cell's layoutSubviews method, but...
* this happens just too late for the label itself to get laid out, and its size remains
* zero. When a subsequent layout call happens (e.g. a rotate, or scrolling the cells offscreen
* and back) then things get fixed back up. However the initial display has completely blank
* values. To fix this, we forcibly re-add it as a subview in both awakeFromNib and prepareForReuse.
* Both places are necessary; one if the xib/storyboard has a nil value to begin with, and
* the other if code explicitly sets it to nil during one layout cycle then sets it back).
* Bug filed with Apple; Radar 18344249 .
*
* This worked fine in iOS7.
*/
@implementation UITableViewCell (IOS8DetailCellFix)
+ (void)load
{
if ([UIDevice currentDevice].systemVersion.intValue >= 8)
{
/* Swizzle the prepareForReuse method */
Method original = class_getInstanceMethod(self, @selector(prepareForReuse));
Method replace = class_getInstanceMethod(self, @selector(_detailfix_prepareForReuse));
method_exchangeImplementations(original, replace);
/*
* Insert an awakeFromNib implementation which calls super. If that fails, then
* UITableViewCell already has an implementation, and we need to swizzle it instead.
* In IOS8 GM UITableViewCell does not implement the method, but they could add one
* in later releases so be defensive.
*/
Method fixawake = class_getInstanceMethod(self, @selector(_detailfix_super_awakeFromNib));
if (!class_addMethod(self, @selector(awakeFromNib), method_getImplementation(fixawake), method_getTypeEncoding(fixawake)))
{
original = class_getInstanceMethod(self, @selector(_detailfix_awakeFromNib));
replace = class_getInstanceMethod(self, @selector(awakeFromNib));
method_exchangeImplementations(original, replace);
}
}
}
- (void)__detailfix_addDetailAsSubviewIfNeeded
{
/*
* UITableViewCell seems to return nil if the cell style does not have a detail.
* If it returns non-nil, force add it as a contentView subview so that it gets
* view layout processing at the right times.
*/
UILabel *detailLabel = self.detailTextLabel;
if (detailLabel != nil && detailLabel.superview == nil)
{
[self.contentView addSubview:detailLabel];
}
}
- (void)_detailfix_super_awakeFromNib
{
[super awakeFromNib];
[self __detailfix_addDetailAsSubviewIfNeeded];
}
- (void)_detailfix_awakeFromNib
{
[self _detailfix_awakeFromNib];
[self __detailfix_addDetailAsSubviewIfNeeded];
}
- (void)_detailfix_prepareForReuse
{
[self _detailfix_prepareForReuse];
[self __detailfix_addDetailAsSubviewIfNeeded];
}
@end
可能还有其他方法 - 如果你可以在合适的时间调用setNeedsLayout,它可能会强制一个额外的布局传递来纠正事情,但我无法找到合适的时间。
编辑:下面的评论表明重新显示的细胞可能是一个问题。因此,更简单的解决方法可能是调用layoutSubviews并在调用Apple的实现之前进行检查。这可以解决所有问题,因为在布局调用期间问题发生了。所以,下面是该版本的修复 - 我很想知道它是否有效。
#import <objc/runtime.h>
@implementation UITableViewCell (IOS8DetailCellFix)
+ (void)load
{
if ([UIDevice currentDevice].systemVersion.intValue >= 8)
{
Method original = class_getInstanceMethod(self, @selector(layoutSubviews));
Method replace = class_getInstanceMethod(self, @selector(_detailfix_layoutSubviews));
method_exchangeImplementations(original, replace);
}
}
- (void)_detailfix_layoutSubviews
{
/*
* UITableViewCell seems to return nil if the cell type does not have a detail.
* If it returns non-nil, force add it as a contentView subview so that it gets
* view layout processing at the right times.
*/
UILabel *detailLabel = self.detailTextLabel;
if (detailLabel != nil && detailLabel.superview == nil)
{
[self.contentView addSubview:detailLabel];
}
[self _detailfix_layoutSubviews];
}
@end
编辑:在iOS9中修复了此错误。因此,条件可以更改为:
if ([UIDevice currentDevice].systemVersion.intValue == 8)
如果应用程序只需要支持iOS9及更高版本,则可以删除swizzle修复类别。
答案 2 :(得分:4)
几天过去了,我想我必须使用解决方法:
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.without setNeedsLayout];
}
这有明显的延迟,但这是我能找到的唯一方法,使文字在iOS8上显示和可读。
答案 3 :(得分:3)
确认。如果将其初始化为nil,则iOS8不会绘制detailText。这条简单的线应该可以解决问题。
self.detailTextLabel.attributedText = [[NSAttributedString alloc] initWithString:@" "];
答案 4 :(得分:1)
我遇到了同样的问题,我在cellForRowAtIndexPath
之前调用cell.layoutSubviews()
返回单元格。它解决了这个问题。
答案 5 :(得分:1)
我在iOS8上看到了这个问题的两个原因。
如果将详细信息标签中的文本设置为nil或“”(完成此操作的最常见位置是prepareForReuse和/或从故事板中删除默认文本) [如上面的答案中所示,此问题已在iOS9中解决]
如果您子类化字幕类型的UITableViewCell,然后以编程方式注册您在故事板中创建的单元格。 [这是编程错误,您无需注册在故事板中创建的原型单元格]