koogawa blog

iOS、Android、foursquareに関する話題

iOS 7: Dynamic Typeに対応したUITableViewを作ってみた

前回書いた「iOS 7から追加されたDynamic Typeを使ってみた」の続編です。

新しくわかったこと

前回は「UIFontDescriptor を使う必要がある」と書きましたが、その後の調査で

 + (UIFont *)preferredFontForTextStyle:(NSString *)style

メソッドを使えば Dynamic Type に対応できることがわかりました。

このメソッドではフォントのサイズではなく、スタイルを定義します。*1スタイルには次の値を指定できます。

  • UIFontTextStyleHeadline
  • UIFontTextStyleBody
  • UIFontTextStyleSubheadline
  • UIFontTextStyleFootnote
  • UIFontTextStyleCaption1
  • UIFontTextStyleCaption2

各スタイルがどのように表示されるか、いろいろ試してみると面白いです。

f:id:koogawa:20131009235925j:plain
(c)Apple

今回作ったもの

前回は、UITextView を Dynamic Type に対応させるだけでしたが、今回は UITableView 全体のテキストを Dynamic Type に対応させ、さらに文字サイズに合わせて各セルの高さを自動調整するところまで試してみました。

実装方法

まずは、様々な長さのテキストを各セルに表示するだけのUITableViewを作成します。

f:id:koogawa:20130923005612p:plain

高さの調整はしていないので、長いテキストは途中で省略されてしまいます。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

    

    // Configure the cell...

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

    cell.textLabel.numberOfLines = 0;

    cell.textLabel.text = [_textArray objectAtIndex:indexPath.row];

    

    return cell;

 

}

セルのフォントサイズは preferredFontForTextStyle メソッドによって指定されているので、この時点で一応 Dynamic Type には対応しています。

高さの調整

今度は、テキストの長さによってセルの高さを調整してみます。

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

{

    NSString *text = [_textArray objectAtIndex:indexPath.row];

    UIFont *nameLabelFont = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];

    

    CGFloat PADDING_OUTER = 10;

    CGRect totalRect = [text boundingRectWithSize:CGSizeMake(self.tableView.frame.size.width, CGFLOAT_MAX)

                                          options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)

                                       attributes:[NSDictionary dictionaryWithObject:nameLabelFont forKey:NSFontAttributeName]

                                          context:nil];

    return totalRect.size.height + PADDING_OUTER;

 

}

セルの高さは

- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(NSDictionary *)attributes context:(NSStringDrawingContext *)context;

(長い!^^;)メソッドを使って計算しています。

これまでよく使われていた sizeWithFont 系のメソッドは、iOS 7から Deprecated になったようです。

また、設定画面で文字サイズが変更された通知(UIContentSizeCategoryDidChangeNotification)を受け取り、UITableView全体をリロードするようにします。

- (void)viewDidLoad

{

    [super viewDidLoad];

    

    [[NSNotificationCenter defaultCenter] addObserver:self

                                             selector:@selector(preferredContentSizeChanged:)

                                                 name:UIContentSizeCategoryDidChangeNotification

                                               object:nil];

}

 

- (void)preferredContentSizeChanged:(NSNotification *)aNotification

{

    // refresh tableView

    [self.tableView reloadData];

}

これでテキストに合わせてセルの高さを調整してくれるようになりました。

f:id:koogawa:20130923010144p:plain

設定画面から文字サイズを大きくしても、ちゃんと高さを調整してくれます。

f:id:koogawa:20130923010237p:plain

今回のサンプルソース

こちらに置いておきます。

https://github.com/koogawa/DynamicTypeDemo

参考にさせていただいた記事

*1:HTMLでいう物理要素と論理要素に似ていると思いました。これまでは前者で、iOS 7からは後者