こんにちは、iOSアプリ黒帯の林(@kazuhiro494949)です。
先日、ヤフーのiOSアプリ内で利用されているコードを一部切り出してOSSとして公開しました。
https://github.com/yahoojapan/UICollectionViewSplitLayout
このOSSを使うと、リストやグリッドで表示されているデータを画面サイズに合わせてレスポンシブに並べることができます。
(図1)左は1カラムで縦に要素を並べている。右は2カラムで横並びに要素を並べている
iOSのユニバーサルアプリ1で上記のようなデザイン要件を受け、既存の仕組みでは実現することが難しかったため開発しました。本記事では、その技術的な課題を解説し、解決策としてのOSSを紹介したいと思います。
UICollectionViewとUICollectionViewLayout
はじめに、UICollectionViewというiOSアプリ開発において重要なクラスのひとつを簡単に説明します。
iOSアプリでは、たくさんの要素を画面上に配置するためにUICollectionViewというクラスが選択肢の一つとして使われます。このクラスを使うと、例えば大量の写真サムネイルがグリッド上に並ぶといったUIを、必要十分なパフォーマンスで実装することができます。また、データ管理とレイアウト計算を分けて考えることができるよう設計されており、レイアウトの柔軟なカスタマイズが可能になっています。
個々の要素はItemという概念で取り扱い、さらにそれらをまとめたSectionという上位の概念で全体のリストを管理します。
(図2)UICollectionViewのSectionとItem
レイアウトを変更したい場合には、UICollectionViewLayoutを継承したレイアウト計算クラスを作ります。それをUICollectionViewに渡すと、任意のレイアウトへ変更できます。
(図3)例えばグリッド形式とカバーフロー形式で同じデータを使いながらレイアウトを切り替えるといったことができる
このレイアウト計算クラス部分が、今回公開したOSSです。
UICollectionViewSplitLayout
iOS SDKには標準でUICollectionViewFlowLayoutというレイアウト計算クラスが実装されています。特に何も指定しなければこれがレイアウトを行います。
UICollectionViewFlowLayoutはセクションを縦もしくは横方向へ一直線に並べていきます。
(図4)左は垂直方向へスクロールさせる設定にした場合。右は水平方向へスクロールさせる設定にした場合。
使う側としては要素のサイズを指定するだけで勝手にレイアウトが決まっていくためとても楽なのですが、今回の要件のようなレスポンシブなレイアウトを実現することはできません。
従来の方法では実現できないこのレイアウトを実現するために新しく作ったのがUICollectionViewSplitLayoutです。
このレイアウト計算クラスの基本的なアイデアは、セクションを2カラムに分割して並べるという1点のみです。UICollectionViewSplitLayoutでは課題を解決するために、画面全体を2カラムで構成して各セクションを左右どちらに並べるか指定できるという仕様を持っています。左右の幅の比率もパラメータとして渡すことができ、任意のタイミングで2カラムと1カラムを切り替えることができます。
(図5)セクションごとに色を分けて表示させている。Portraitでは全てのセクションを上から下に表示させ、Landscapeでは2番めのセクションを右カラムに移している (yahoojapan/UICollectionViewSplitLayoutのWhat’s thisより抜粋)
アイデアはとてもシンプルなのですが、これによって簡単にUICollectionViewを使ったレスポンシブUIの実現ができるようになりました。それぞれの画面パーツには変更を加えず、そのレイアウトを柔軟に1カラムと2カラムで切り替えられます。
このクラスを使った詳細な実装方法は、READMEの”Getting Started”を御覧ください。
またライブラリを使った実装のサンプルコードも同じリポジトリで公開しているので、実際にライブラリを導入したUIを動かしていただけるようになっています。是非ダウンロードして実行してみてください。
UIStackViewとUICollectionView
UICollectionViewSplitLayoutのようなUIを実現する別の方法として、UIStackViewを使うという選択肢もあるでしょう。UIStackViewを使うと簡単に要素を並べていく事ができます。
UIStackViewは並びを垂直方向と水平方向で動的に切り替えることができ、それを階層化することで見かけ上同じ動きが実装できます。そのため、リスト形式に要素を並べる方法の一つとして活用するケースも増えてきています。
しかし、もともとの用途とそれに伴う内部的なアーキテクチャはUICollectionViewと異なります。従って計算コストやメモリ効率の面を考えても完全に置き換えられるわけではありません。特に画像を含む要素を数多く並べたいといった用途で素直に使ってしまうと危険です。UIStackViewの内部的な仕組みについてまとめた資料があるので、そちらも合わせて参照していただけると幸いです。
まとめ
UICollectionViewの標準の仕組みでは作りにくいタイプのレスポンシブUIを実現する方法を考えました。そして、その実装をOSSとして公開させていただきました。ぜひご利用ください。もちろん、IssueやPull Requestもお待ちしています。
https://github.com/yahoojapan/UICollectionViewSplitLayout
参考資料
- [1] UICollectionView - UIKit, https://developer.apple.com/documentation/uikit/uicollectionview
- [2] UICollectionViewLayout - UIKit, https://developer.apple.com/documentation/uikit/uicollectionviewlayout
- [3] UICollectionViewFlowLayout UIKit, https://developer.apple.com/documentation/uikit/uicollectionviewflowlayout
- [4] UIStackView UIKit, https://developer.apple.com/documentation/uikit/uistackview
- [5] UIStackView demystified, https://speakerdeck.com/kazuhiro4949/uistackview-demystified
※1 iPhoneとiPadに対して共通のコードベースで提供する仕組み
こちらの記事のご感想を聞かせください。
- 学びがある
- わかりやすい
- 新しい視点
ご感想ありがとうございました