Think Big Act Local

iPhone開発を軸にブレブレの記事を書いていきます。

SmartNews風のレイアウトをInterface Builderを使ってつくる

今回はSmartNewsのような動的レイアウトを作ってみます。

SmartNews | 話題のニュースがサクサク読めるスマホアプリ

完成イメージ

こういった画面を目指します。

f:id:himaratsu:20130529230148p:plain

(サムネ画像はとりあえずのサンプル画像)

アプリ設計の構想

Interface Builderを使って作ります。
UIViewControllerをベースにして、

  • UIView → タイトルバー(Beaunosy)
  • UIView → アップデート日時バー(5/26(日) 20:54 発行)
  • UITableView → 記事レイアウト部分

という構成です。

記事レイアウト部分の設計

上述した通りUITableViewがベースです。このテーブルビューに読み込ませるセルを動的にします。動的といっても単に複数のxibファイルを用意し、それを順番に読みこませるだけです。
今回は以下の3パターンのxibファイルを使いました。

パターンA(1x1)

f:id:himaratsu:20130529223726p:plain

パターンB(1x3)

f:id:himaratsu:20130529223826p:plain

パターンC(3x1)

f:id:himaratsu:20130529223840p:plain

(サムネ画像は適当)

テーブルビューの描画

今回は分かりやすくするため、xibの組み合わせパターンは固定とします。

index xibパターン
0, 5 パターンB(1x3)
1, 3, 4, 6 パターンA(1x1)
2 パターンC(3x1)

セルの高さの指定

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    // 1x3 or 3x1
    if (indexPath.row == 0
        || indexPath.row == 2
        || indexPath.row == 5) {
        return 240;
    }
    // 1x1
    else {
        return 109;
    }
}

xibファイルの登録

- (void)viewDidLoad
{
    [super viewDidLoad];

    // カスタムCellを登録
    [self.tableView registerNib:[UINib
                                 nibWithNibName:@"Article1x1TableViewCell"
                                 bundle:[NSBundle mainBundle]]
         forCellReuseIdentifier:@"Cell1x1"];
    [self.tableView registerNib:[UINib
                                 nibWithNibName:@"Article1x3TableViewCell"
                                 bundle:[NSBundle mainBundle]]
         forCellReuseIdentifier:@"Cell1x3"];
    [self.tableView registerNib:[UINib
                                 nibWithNibName:@"Article3x1TableViewCell"
                                 bundle:[NSBundle mainBundle]]
         forCellReuseIdentifier:@"Cell3x1"];
}

セルの描画

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    // 1x3 or 3x1
    if (indexPath.row == 0
        || indexPath.row == 2
        || indexPath.row == 5) {
        
        NSString *CellIdentifier = nil;
        if (indexPath.row == 0 || indexPath.row == 5) {
            CellIdentifier = @"Cell3x1";
        }
        else {
            CellIdentifier = @"Cell1x3";
        }
        Article1x3TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        
        NSInteger rowNumber = indexPath.row*4;
        cell.rowNumber = rowNumber;
        cell.leftFeed = _feedList[rowNumber];
        cell.rightTopFeed = _feedList[rowNumber+1];
        cell.rightMiddleFeed = _feedList[rowNumber+2];
        cell.rightBottomFeed = _feedList[rowNumber+3];
        cell.delegate = self;
        
        return cell;
    }
    // 1x1
    else {        
        Article1x1TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell1x1"];
        
        NSInteger rowNumber = indexPath.row;
        cell.rowNumber = rowNumber*2;
        cell.leftFeed = [_feedList objectAtIndex:rowNumber*2];
        cell.rightFeed = [_feedList objectAtIndex:(rowNumber*2+1)];
        cell.delegate = self;
        
        return cell;
    }
}

_feedListというのはNSMutableArray型のインスタンス変数で、
表示する記事の情報が入っている想定です。

Article1x1TableViewCell や Article3x1TableViewCell は UITableViewCell の拡張クラスで、feedオブジェクトがセットされるとIBOutletが更新されるようになっています。

実行結果

当初想定した通りのものが出来たでしょうか?
一見複雑そうな動的レイアウトですが、InterfaceBuilderを使えば簡単ですね。

f:id:himaratsu:20130529230148p:plain

あとはxibファイルの組み合わせロジックを作りこめば動的レイアウトの完成です。

関連書籍

UI/UXにこだわるクックパッドのデザイナーの方の著書。
細かいレイアウトなど非常に参考になります。