如何让自定义UITableViewCell获取用户对首选文本大小的更改?

时间:2014-01-16 22:02:40

标签: ios uitableview dynamic-text

我正在开发一个简单的应用程序来在表格视图中显示项目。如果我从UITableViewCell返回一个普通的tableView:cellForRowAtIndexPath对象:

static NSString *cellIdentifier = @"EmailCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:
    cellIdentifier];

if (!cell) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 
        reuseIdentifier:@"EmailCell"];
}

cell.textLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];

...然后与动态文本的交互按预期工作;如果用户转到Settings | General | Text Size,更改滑块值,然后返回到我的应用程序,所有可见单元格立即更新自己以使用新的字体大小。

但是,如果我返回UITableViewCell的自定义子类,其中XIB包含设置为使用文本样式而不是系统字体的UILabel,则动态文本无法正常工作。以下是我用来将{XIB»分配给viewDidLoad中的表格的代码:

[self.table registerNib:[UINib nibWithNibName:@"EmailCell"
                                           bundle:[NSBundle mainBundle]]
     forCellReuseIdentifier:@"EmailCell"];

然后在tableView:cellForRowAtIndexPath:

中使用此代码
static NSString *cellIdentifier = @"EmailCell";
EmailCell *cell = (EmailCell *)[tableView 
    dequeueReusableCellWithIdentifier:cellIdentifier];

首次运行应用时,可见单元格的文本大小与用户选择的首选文本大小相匹配。但是,如果我转到设置并更改该大小然后返回到我的应用程序,则所有可见单元格都保留以前的文本大小。如果我然后向上滚动,我会看到两个单元格显示新的(正确的)文本大小,但其余的仍然是旧的大小。如果我停止并重新启动应用程序,现在所有单元格都会显示新的(正确的)文本大小。

对我来说,似乎很明显,tableview将先前大小的单元格保留在队列中,而不是自动更新其字体大小以响应用户对首选文本大小的更改。但是我不明白为什么tableview 在队列包含普通的非子类UITableViewCell实例时自动进行此更改。有没有什么办法可以让我无需重新启动应用程序就可以工作(或者不重新创建UITableView实例,从而清空队列)?有没有办法以编程方式(并合法地)清除此队列?

编辑:如果有人对这个问题感兴趣,我的插件修补就是编写一个通用的实用工具方法来创建一个新的tableview,复制原始tableview中的所有相关属性(包括注册的单元类)然后将旧的交换为旧的。由于这是一个新表,因此它会生成包含新文本大小的排队单元格的全新实例。

3 个答案:

答案 0 :(得分:1)

现在可以在iOS 10中为您处理。

http://useyourloaf.com/blog/auto-adjusting-fonts-for-dynamic-type/

在您的标签上将adjustsFontForContentSizeCategory设置为YES / true,当文字大小首选项更改时,它会自动调整大小。

答案 1 :(得分:0)

根据您所描述的内容,您可能只是想在用户对其进行背景化后,在视图返回屏幕时随时重新加载表格。为了实现这个我想你想要的方式,你需要在你的tableView的init方法中添加以下内容 - 它会告诉你的tableView在应用程序即将进入前台时正确地重新加载单元格:

[[NSNotificationCenter defaultCenter] addObserver:self.tableView selector:@selector(reloadData) name:UIApplicationWillEnterForegroundNotification object:nil];

这样,如果用户在转到手机设置后打开应用程序返回到视图,则应重新加载tableView并正确反映更改(如果有的话)。

您可以在此处看到我测试结果的快速视频:

https://www.dropbox.com/s/pvjuiyofydnxnvd/textsize.mov

编辑:

就像你在之前的评论中所说的那样,你的nib实现似乎有问题。唯一的区别是更新label属性的位置/方式。在自定义单元格中,我创建了一个label属性和一个font属性,并将标签添加到init中的单元格中,而在layoutSubviews中我覆盖了该字体。这是代码:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    LabelCell *cell = [tableView dequeueReusableCellWithIdentifier:@"LabelCell"];

    if (cell == nil) {
        cell = [[LabelCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"LabelCell"];
    }

    cell.myLabel.text = _items[indexPath.row];
    cell.myFont = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];

    return cell;
}

在细胞本身:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];

    self.myLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, self.contentView.frame.size.width - 20, 34)];
    self.myLabel.backgroundColor = [UIColor greenColor];
    [self.contentView addSubview:self.myLabel];

    return self;
}

- (void)layoutSubviews {
    [super layoutSubviews];

    self.myLabel.font = self.myFont;
}

以下是使用带标签的自定义单元格的相同结果:

https://www.dropbox.com/s/ow2zkb6j9yq2c3m/labelcells.mov

关于“清除队列”,单元格在它们即将显示在屏幕上之前不会排队,您可以通过在使用标识符将单元格出列后立即记录计数器值来查看。如果现在屏幕上有10个单元格,它只会使10个单元格出列。这就是为什么你使用代码if(!cell){在这里做所有单元格常见的东西}的原因然后你做了特定于每个单元格的事情,以及为什么这个代码工作,即使你假设reloadData没有“清除队列”,我不相信在阅读UITableView文档之后也不会这样做。

答案 2 :(得分:0)

我的直接修复方法是编写一个通用实用程序方法,该方法生成一个新的tableview,从原始tableview(包括已注册的单元类)复制所有相关属性,然后将旧的替换为旧的。由于这是一个新表,因此它会生成包含新文本大小的排队单元格的全新实例。