UICollectionView で UITableView のセクションヘッダー風の SupplementaryView を実装する

UICollectionView は昔なら UITableView を使って頑張って実装していようなグリッドレイアウトな UI を UITableView ライクな I/F で実装できる素敵なやつです。UITableView ライクな I/F とは言いましたが実は細かい挙動が UITableView とは違っています。UICollectionView で UITableView のセクションヘッダーのようなものを実装するには SupplementaryView を使います。でも普通に UICollectionViewFlowLayout を使っても SupplementaryView はスクロールすると Cell と同じようにそのまま通り過ぎてしまいます。UITableView のセクションヘッダーみたいに同一セクション内の場合に上端に居続けてくれません。UITableView のセクションヘッダーみたいなフローティングした(上端に張り付いたような)セクションヘッダーを実装したい。じゃあ、似たような挙動になるようにしようっていうのが今回の話です。

とりあえずググる

特にライブラリとしてまとまっているものが見つけられませんでした。(あとで調べたら vast-eng/uicollectionview-gridlayoutというのがありました。)しかし、stackoverflow で同じようなことをしたいという質問が見つかりそこから gist に上げられたコードを見つけました。

Sticky Headers at the top of a UICollectionView

やや難あり

さっきの gist ですが、確かに UITableView のセクションヘッダーみたいに同一セクション内の場合に上端に居続けてくれるのですが、全体的に位置が下がり気味。何かが違う。

どノーマルの UICollectionViewFlowLayout を使ったものがこちら

f:id:griffin-stewie:20131020120023p:plain

gist のコードをそのまま適用したのがこちら

f:id:griffin-stewie:20131020120021p:plain

修正

ずれる理由は UICollectionViewFlowLayoutsectionInset の値が考慮されていませんでした。修正後のコードはこちら。

UIEdgeInsets sectionInset = self.sectionInset;

origin.y = MIN(
                MAX(
                    contentOffset.y + cv.contentInset.top,
                    (CGRectGetMinY(firstObjectAttrs.frame) - topHeaderHeight - sectionInset.top)
                    ),
                (CGRectGetMaxY(lastObjectAttrs.frame) - bottomHeaderHeight + sectionInset.bottom)
                );

公開

修正したコードを UICollectionViewFlowLayout のサブクラスとして github にあげています。もし使えそうなら使って見てください。

CSNFloatingHeaderViewFlowLayout

CocoaPods でインストールできます。

pod 'CSNFloatingHeaderViewFlowLayout', '~> 0.0'

Thank you toblerpwn.