UICollectionViewを使うとタイル上に任意のView(セル)を表示できます。今回はサンプルを交えてUICollectionViewの説明をしたいと思います。

サンプルコード: https://github.com/stack3/UICollectionViewSample

サンプルを起動して、UICollectionViewを選択すると、以下の画面表示されます。

01

02

セルを選択すると、そのセルは青くなって以下のようにAlertが表示されます。

10

UICollectionViewのセルの再利用

UITableView同様にUICollectionViewもセルの再利用という概念があります。

表示する項目数が1000とかたくさんあった時に、セル(UICollectionViewCell)を1000個作るとメモリ効率がすごく悪くなります。なぜかというと実際に画面に表示されるセルは一部だけだからです。つまり必要なセルはその分くらいで良いのです。(実際にはスクロール時のガタツキをなくすなどの理由で、必要な数は表示分+αとなります)。

今回のサンプルも50項目表示していますが、1画面に収まるのは25項目です。

14

よって25+α分のセルを生成して、スクロールアウトした項目は新たにスクロールインした項目で再利用するとメモリを圧迫しません。

13

このセルの再利用の仕組みは、UICollectionViewが持っています。よってプログラミングは簡単です。ただ、なぜセルの再利用が必要かを覚えておいたほうが理解が進むでしょう。

STCollectionItemクラス

セルの表示元となるデータを格納するクラスです。

@interface STCollectionItem : NSObject

// 番号
@property (nonatomic) int number;
// 番号下に表示するキャプション
@property (strong, nonatomic) NSString *caption;

@end

このクラスのオブジェクトは50項目分作ることになります。ただしセルのオブジェクトに比べれば比較にならないほどサイズが小さいので問題ありません。

STCustomCollectionViewCellクラス

セルとなるクラスです。UICollectionViewCellのSubclassとして作ります。

@interface STCustomCollectionViewCell : UICollectionViewCell

プロパティを宣言。一応、外からは読み専用ということでreadonlyにしてあります。

@property (weak, nonatomic, readonly) IBOutlet UILabel *numberLabel;
@property (weak, nonatomic, readonly) IBOutlet UILabel *captionLabel;
  • numberLabel – 正方形で中心に数値を表示するためのLabel
  • captionLabel – 数値の下に表示するキャプション用のLabel

STCustomCollectionViewCell.hで、選択時の背景色を設定します。これはselectedBackgroundViewプロパティを使います。今回は生成したViewのbackgroundColorを青にしたものをプロパティに設定しています。

- (void)awakeFromNib
{
    self.selectedBackgroundView = [[UIView alloc] initWithFrame:self.bounds];
    self.selectedBackgroundView.backgroundColor = [UIColor blueColor];
}

ここはUIImageViewにすれば画像を貼ることもできるでしょう。

STCustomCollectionViewCell.xib

今回はセルのレイアウトをInterface Builderで作っています。まずはUICollectionViewCellを配置する必要があります。

04

Viewがある場合は削除してからUICollectionViewCellを配置してください。Viewに配置しないように気をつけましょう。

配置したUICollectionViewCellの上に、numberLabelとcaptionLabelとなる2つのUILabelを配置しています。

03_edited-1

STCustomCollectionViewCellクラスとプロパティをひもづける必要があります。xib上のCollectionViewCellを選択して以下の項目を設定します。

Identity InspectorのCustom ClassをSTCustomCollectionViewCellとする。

05

Connections InspectorのOutletsで、プロパティと配置したLabelをひもづける。

06

※ xibとカスタムViewのひもづけは、こちらでも解説しています。 http://blogios.stack3.net/archives/195

STCollectionViewSampleControllerクラス

STCollectionViewSampleController.hで、UICollectionViewDataSourceとUICollectionViewDelegateを実装するように宣言しておきます。

@interface STCollectionViewSampleController : UIViewController<UICollectionViewDataSource, UICollectionViewDelegate>

@end

STCollectionViewSampleController.mで、UICollectionView(_collectionView)と項目データを入れる配列(_items)を宣言。

@implementation STCollectionViewSampleController {
    IBOutlet __weak UICollectionView *_collectionView;
    __strong NSMutableArray *_items;
}

initメソッドで_itemsを初期化。STCollectionItemオブジェクトを50個格納します。

_items = [NSMutableArray arrayWithCapacity:50];
for (int i = 0; i < 50; i++) {
    STCollectionItem *item = [[STCollectionItem alloc] init];
    item.number = i+1;
    item.caption = [NSString stringWithFormat:@"caption%d", item.number];
    [_items addObject:item];
}

viewDidLoadで、UICollectionViewが項目表示する時に使うセルのxibを登録します。これはUICollectionView#registerNib:forCellWithReuseIdentifier:で行います。

- (void)viewDidLoad
{
    [super viewDidLoad];
    // STCustomCollectionView.xibを指定して(.xibは省略)、UINibオブジェクトを生成
    UINib *nib = [UINib nibWithNibName:@"STCustomCollectionViewCell" bundle:nil];
    // UICollectionViewに項目表示に使うセルとして登録
    [_collectionView registerNib:nib forCellWithReuseIdentifier:@"CellId"];

UITableViewのときと同じくセルを再利用するためのIDを指定します。今回は表示するセルのクラスは全て同じです。よって特に意識しなくてもよく、単に”CellId”としています。

※ 項目ごとに異なるクラスのセルを使う場合は、それに応じてIDを変える必要があります。これは別の回で解説します。

dataSourceとdelegateプロパティも設定しておきます。これもxib上でできますが、自分はレイアウト以外はプログラムでやるほうがしっくりくるので、ここで設定しています。

    _collectionView.dataSource = self;
    _collectionView.delegate = self;
}

これでUICollectionViewDataSourceとUICollectionViewDelegateのメソッドが呼び出されるようになります。

UICollectionViewDataSource

以下のDataSourceメソッドで全体の項目数を返します。つまり_itemsの要素数です。

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return _items.count;
}

以下のDataSourceメソッドで項目の内容をセルに反映させて返します。

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    // セルオブジェクトを得る
    STCustomCollectionViewCell *cell = [_collectionView dequeueReusableCellWithReuseIdentifier:@"CellId" forIndexPath:indexPath];
    // 指定位置のSTCollectionItemオブジェクトを得る
    STCollectionItem *item = [_items objectAtIndex:indexPath.row];
    // セルオブジェクトのプロパティを設定する
    cell.numberLabel.text = [NSString stringWithFormat:@"%d", item.number];
    cell.captionLabel.text = item.caption;

    return cell;
}

UICollectionView#dequeueReusableCellWithReuseIdentifier:forIndexPath:は、

  • 再利用できるセルがあればそれを返す
  • 再利用できるセルがなければ生成してそれを返す

という挙動をします。適切な再利用IDを指定すれば深く意識する必要はないでしょう。今回はUICollectionView#registerNib:forCellWithReuseIdentifier:で指定した”CellId”をここでも指定するだけです。

dequeueReusableCellWithReuseIdentifierが返したセルオブジェクト(STCustomCollectionViewCell)のnumberLabel、captionLabelプロパティを通じて、STCollectionItemのnumberとcaptionを設定します。

UICollectionViewDelegate

以下のDelegateメソッドはセルが選択された時に呼ばれます。

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    STCollectionItem *item = [_items objectAtIndex:indexPath.row];
    NSString *message = [NSString stringWithFormat:@"%dn%@", item.number, item.caption];

    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil
                                                        message:message
                                                       delegate:nil
                                              cancelButtonTitle:nil
                                              otherButtonTitles:@"OK", nil];
    [alertView show];
}

選択されたセルから対応するSTCollectionItemオブジェクトを得て、それを元にmessage文字列を生成。Alertを表示します。

STCollectionViewSampleController.xib

STCollectionViewSampleControllerクラスのレイアウトのxibです。

UICollectionViewをView全体に配置しています。

07

配置する時は画面右下のCollection Viewを選択してドラッグ&ドロップです。

08

配置したUICollectionViewを選択してSize Inspectorを選択すると以下の様な表示になります。

11

 

ここでセルのサイズや間隔などを指定します。今回はセルのサイズのみ指定して、間隔などは0にしておきます。これでセルが敷き詰められて表示されます。

File’s OwnerのConnections Inspectorでメンバ変数_collectionViewとひもづけも忘れずに。

09

 

以上で今回のサンプルの説明は終わりです。UICollectionViewの基本的な使い方は説明できたかと思います。

その2へ続く