ぎじゅつめもブログ

主にアプリ開発の技術メモを残していきます。

【Objective-C】UITableViewを Dynamic Type に対応する

UITableViewを文字サイズの変更 (Dynamic Type) に対応する方法です。
(環境: xcode 6.3, iOS8.3)

iOS7から設定アプリ > 一般 > アクセシビリティ から文字サイズを変更できます。
f:id:tsuyushiga:20150419182743p:plain
こちらの設定が変更された際に、設定変更の検知し、フォントサイズとセルの高さを動的に変更する方法を紹介します。

フォントサイズの指定

UITableViewのCellの表示内容を設定するメソッド、もしくはstoryboardなどでフォントサイズをDynamicTypeに対応しているスタイルに設定します。
下記はtableView:cellForRowAtIndexPath:メソッドで設定している例です。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];
    
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:nil];
    }
    
    cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
    cell.textLabel.numberOfLines = 0;

    // フォントサイズのスタイルを設定
    cell.textLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
    cell.detailTextLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleCaption2];
    
    HogeItem* item = [self getItem:incexPath];
    
    cell.textLabel.text = item.text;
    cell.detailTextLabel.text = item.subText;
    
    [cell.textLabel sizeToFit];
    
    return cell;
}
セルの高さを設定

セルの高さを動的にします。

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    HogeItem* item = [self getItem:indexPath];
    
    NSString *text = item.text;
    UIFont *labelFont = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
    CGFloat padding = 40.0;
    CGRect totalRect = [text boundingRectWithSize:CGSizeMake(self.tableView.frame.size.width - 30, CGFLOAT_MAX)
                                          options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                       attributes:[NSDictionary dictionaryWithObject:labelFont forKey:NSFontAttributeName]
                                          context:nil];
    return MAX(totalRect.size.height + padding, 60);
}
フォントサイズ設定変更の検知

最後にDynamicTypeが変更されたことを検知し、設定を反映するようにします。

// viewDidLoadで通知センターにフォントサイズが変更された際に呼ばれるメソッドを登録
- (void)viewDidLoad {
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(preferredContentSizeChanged:)
                                                 name:UIContentSizeCategoryDidChangeNotification
                                               object:nil];
}
// フォントサイズが変更された際に呼ばれるメソッド
- (void)preferredContentSizeChanged:(NSNotification *)aNotification {
    [self.tableView reloadData];
}
ヘッダーのサイズ

また、テーブルにヘッダーがある場合は、下記のようにしてヘッダーのサイズも動的に変更できます。

- (void)sizeHeaderToFit {
    self.headerLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
    
    UIView *header = self.tableView.tableHeaderView;
    
    [header setNeedsLayout];
    [header layoutIfNeeded];
    
    CGFloat height = [header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
    CGRect frame = header.frame;
    
    frame.size.height = height;
    header.frame = frame;
    
    self.tableView.tableHeaderView = header;
}

// tableViewをリロードするタイミングで...
[self sizeHeaderToFit];


以上です。

参考:
iOSアプリで動的にフォントサイズを変更する「Dynamic Type」新機能の実装法 #ios7yahoo|CodeIQ MAGAZINE
ios - table header view height is wrong when using auto layout, IB, and font sizes - Stack Overflow