UICollectionViewのHeaderをxibから出し分ける
UICollectionView vs UITableView
UITableViewのtableHeaderViewのように、UICollectionViewの上端にheaderを入れたい時、collectionView:viewForSupplementaryElementOfKind:atIndexPath:
というメソッドでsectionの先頭にヘッダーを追加すると、UITableViewとは違ってスクロール時に固定されることがない、tableHeaderView
のような見た目を作ることができます。
ただしこの方法で動的にheaderの出し分けを行いたいときは少し工夫が必要です。なぜならstoryboardではsectionに複数のviewを登録しておくことができないためです。
出し分けるview(UICollectionReusableView)をxibで定義する
xibで何種類かのheaderを作成しておきます。
このとき、特にこだわり・実装上の都合がなければ
- 出し分けるxibの名前
- (必要があれば)xibに対応するUICollectionReusableViewのサブクラス名
- collectionViewのreusableIdentifier
- UICollectionViewを管理するクラスで、どのヘッダーを使うかの識別子
を全て同じEnum(文字列)で表現するとわかりやすくなります。
ViewControllerのコード
class CollectionViewController : UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { enum ListType : String { case Default = "CatalogListDefaultHeaderView" case Bookmark = "CatalogListBookmarkHeaderView" case Popular = "CatalogListPopularHeaderView" case Recent = "CatalogListRecentHeaderView" } var listType : ListType = .Default override func viewDidLoad() { super.viewDidLoad() for type in AllListType { let nib = UINib(nibName: type.rawValue, bundle: nil) collectionView.registerNib(nib, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: type.rawValue) } self.flowLayout.headerReferenceSize = CGSize(width: collectionView.frame.width, height: 100) } func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView { var reusableView : UICollectionReusableView! if kind == UICollectionElementKindSectionHeader { reusableView = collectionView.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: listType.rawValue, forIndexPath: indexPath) } return reusableView } }
全体像はざっとこうなるのですが、ポイントはいくつかあります。
だいたいこちらの記事に似たような内容があるのですが、
- headerReferenceSizeに値を入れないとviewForSupplementary...が呼ばれないこと
- viewForSupplementary...で登録されていないviewをいきなり返しても実行時エラーになること
- 表示のタイプをString側のenumで定義しておくと管理が楽
というあたりがポイントです。
UICollectionViewはtableのように使えたり表現力がとても豊かで個人的に好きです。