ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
UI Collection Viewにおけるリスト
UICollectionViewを用いてApp内でリストやサイドバーを構築する方法を学びましょう。Compositional layoutの柔軟性をフルに活用しながら、テーブルビューの外観を置き換えましょう。Modular Layoutのオプションを確認し、Appのデザインオプションとしてこれまで以上に活用する方法を学びましょう。一つのUICollectionView内でテーブルビューのようなリストにカスタムのCompositional Layoutを組み込む方法もご紹介します。リストの扱い方、より手の込んだセルの作り方、またレイアウトをカスタマイズして、App内の情報をより良いデザインで見せる方法も学びます。このセッションを有効活用するには、Compositional Layoutの基礎を理解していることが求められます。更なる情報は、WWDC19の"Advances in Collection View Layout" をご参照ください。
リソース
関連ビデオ
WWDC20
WWDC19
-
ダウンロード
WWDCへようこそ “UI Collection Viewにあるリスト”
皆さんこんにちは フレームワークエンジニアをしています UIKitチームのミシェル・オクスです このビデオでは UICollectionViewの リストについてお話をします
“MODERN COLLECTION VIEWS” ここでご覧になっているのは 最新のCollection View Setupの一部であると 考えているアーキテクチャです このダイアグラムについては“Advances in Collection View”で詳しくお話したいと思います ダイアグラムの様々な部分 それぞれのビデオがあり このビデオは リストコンフィギュレーションと リストセルについてご説明しています
では まず最初に コレクションビューの リストが実際は何であるかをお話しします iOS 14のリストでは 見た目がUITableViewに似た コレクションビューを使用できます iOS 13で導入したCompositional Layoutの上に構築したからです これは とてもフレキシブルであり また高度なカスタム化が可能なのです
また 自動調整サポートを 特にリスト用に強化しました UICollectionViewでリストを使用するときには 自動調整をデフォルトの挙動にしています つまり 皆さんはもう セルの高さを マニュアルで計算する必要がなくなり その代わりに 自動レイアウトを使って セルを簡単に構築するだけ そして コレクションビューが あとはすべてやってくれます もし マニュアルでサイズ調整をする 必要があれば そうすることもできます そのやり方は 皆さんのセルサブクラスで preferredLayoutAttributesFittingAtributesを 上書きして行うことができます
カスタム化の観点に戻って 見ていきましょう 先ほど申し上げた“高度なカスタム化”の 意味をお見せしたいと思います
ここでは アプリケーションを 例としてお見せしていますが ここには 最近使用したすべての絵文字が 最上部に直交方向でスクロール表示されています その下には グループでソートされた 絵文字のアウトラインが表示されており それにはヒエラルキーが埋め込まれています そして 最下部を見ると UITableViewに とても外観の似たものが表示されており それに加えて 各々のセルをスワイプして お好みの絵文字を マーキングすることもできます これは リスト組み合わせとCompositional Layoutを用いたコレクションビューの一例です これがどう作用するかを深掘りする前に リストのコンポーネントを見てみましょう
iOS 14では UICollectionLayoutListConfiguration というまったく新しいタイプをご提供しています レイアウト側でコレクションビュー内にリストを 構築する時に必要となる唯一の新しいタイプです UICollectionLayoutListConfigurationは NSCollectionLayoutSectionと UICollectionViewompositionalLayoutの 上に構築されており この2つは iOS 13で導入した 既存の Compositional Layoutシステムの構成パーツです
今回 Compositional Layoutの 詳細は説明はしませんが ぜひ WWDC2019の“Advances in Collection View Layout”ご参照ください
“LIST CONFIGURATION” それでは リストコンフィギュレーションを 見てみましょう
リストコンフィギュレーションは スタイルとして お馴染みのTableViewと 同じ外観となっています プレーンとグループ そしてインセットグループです しかし ここで UICollectionViewのリストだけの 新しいスタイルを2つ ご紹介します これは “サイドバー”と “サイドバープレーン”と呼ばれています この新しいスタイルを使って iPadOS 14で 驚くほど素晴らしいマルチカラムの アプリケーションを構築することもできます 更に 全体の見た目とは別に リストコンフィギュレーションにより セパレータを見せる 隠すといったオプションや リストのヘッダーやフッターを構築する といったオプションも可能になりました リストコンフィギュレーションの技術用語は UITableViewをお使いなら ご存じですよね でも 今回 いくつかの新しい用語を 付け加えましたので この後お話いたします ではまず最初に リストの作り方をお見せしましょう
最も簡単な方法は UICollectionLayoutListConfigurationを 作成し ここに 外観を設定し このコンフィギュレーションを使い UICollection ViewCompositionalLayoutを作成することです
この例では insetGroupedスタイルを使っています これにより 見た目は insetGrouped UITableViewと全く同じになりますし このレイアウト内のすべての セクションも まったく同じ外観になります
ですから UITableViewととても似ているのです 皆さんには このアプローチを可能な限り 使っていただきたいと思います しかし リスト作成には もっとパワフルなやり方があり それを私たちは persection設定と呼んでいます
persection設定では まったく同じ コンフィギュレーションを使いますが これで構成レイアウトを作成する代わりに コンフィギュレーションを使い NSCollectionLayoutSectionを作ります
このコードは Compositional Layout上の 既存のセクションプロバイダ― イニシャライザーの中で使うことができます このコードは コレクションビューの 各々のセクションで呼び出され 該当するセクションに特化した 個別のレイアウト 定義を返すことができるようになります
その結果 ここで表示されているものは 先ほどお見せしたシンプルセットアップと 全く同様のデザインとなります でも このセットアップが手元にあるので 私たちの好みのレイアウトに セクションごとに カスタム化できるようになりました
例えば 最初のセクションには カスタムグリッドレイアウトを返していますが このグリッドは 既存の構成レイアウトAPIを使って構築しました これはとてもパワフルで レイアウトにも 使うことができ 先ほどのお見せした 最近使った絵文字を直交方向にスクロール表示 していた あのスクリーンなどがそうです ここまで UICollectionViewでの リストの作り方をご覧いただきましたが 次に リストセクションでヘッダーとフッターを どう構成 設定するのか お話しましょう “HEADERS AND FOOTERS” コレクションビュー内のリストにある ヘッダーとフッターは UITableViewで慣れているものとは 使い方が少し異なるかもしれません UICollectionView内のリストの ヘッダーとフッターは 明示で有効化されていなければならず そのやり方は2つあります
一つは 皆さんのヘッダーとフッターを 追加ビューとして登録する方法です この例では ヘッダーを構成しますが 同じコードはフッターでも使えます シンプルにここで コンフィギュレーションの ヘッダーモードかフッターモードを “supplementary”に設定します
次に コンフィギュレーションを このように設定すると コレクションビューは ヘッダーやフッターを 画面上に描画するタイミングで 追加ビューを提供するように聞いてきます
このビューを提供するもっとも簡単なやり方は 差分最適データソースにある 追加ビュー プロバイダを使う方法がありますが またUICollectionViewのデリゲートに 同様の方法を実装することでも可能です
このコールバックの内部で 要素の種類を elementKindSectionHeaderか または elementKindSectionFooterか を チェックし 構成をし そして適切なビューを返します
大切なのは このアプローチをするときは コレクションビューからの要請があれば― 追加ビューを提供しなくてはならないことを 忘れないことです もし 追加ビューコールバックで nilを返したら コレクションビューが アサートします レイアウト内で ヘッダーをリクエストしてくる セクションと してこないセクションがある場合は 先ほどお見せした persectionコンフィギュレーションを使い 対象のセクションが ヘッダーを 表示すべきか そうでないかにより モード設定を “supplementary” または“none”にしてください ここには オプションが2つあると 先ほど申し上げました 2つ目のオプションは ヘッダーだけに当てはまります これは ヘッダーモードを firstItemInSectionへ 設定することで 有効化されます これは コレクションビューに この対象セクションで 最初のセルだけを構成し ヘッダーのような 外観にするように指令しているのです
ヒエラルキーデータ構成と 新規のセクション スナップショットAPIを使っているときには おすすめのモードです さらにご興味がおありでしたら“Advances in Diffable Data Source”をご参照ください しかし このモードを使っているときは データ ソースはそれを認識している必要があります その理由は そのデータソースの 最初のアイテムは もはや セクションの 実際のコンテンツを表現しておらず そのセクションのヘッダー もしくはタイトルを 表しているに過ぎないからです コレクションビューのリストのレイアウトに ついてお話しましたので 表現の話をしましょう iOS 14では 新しいUICollectionView セルサブクラスを導入しています これは UICollectionViewListCellといいます
これは ぜひとも申し上げたいのですが コレクションビューの構成の性質上 リストセルは 通常のコレクションビューセルが 表示できる場所では どこでも使用できます また リストセクションと一緒に どの UICollectionViewセルを使うことも可能です 皆さんの必要なAPIの断片的に拾い集め 目的通りの設計を達成することもできます リストセルが役に立つ そのピースを見てみましょう
セパレーターのインセットや セルの コンテンツのインデントを構成するたに リストセルには きめ細かいサポート機能が 実装されています UITableViewとは対照的ですが スワイプアクションも 今はセルの機能の一部となっています
更に 素晴らしく改善強化した アクセサリAPIもご用意しています そして いろいろと全容を学習できる デフォルトシステムコンテンツと バックグラウンド コンフィギュレーションへのアクセスが “Modern Cell Configuration”にて可能です
“SEPARATORS” それでは ここでセパレータについて お話をしましょう
ここで セルの例をご覧いただけますが 画像とラベル そしてその下にある セパレータを セルが描画しています これは よくあるレイアウトです しかし ここで皆さんお気づきのように ここでご覧になれるレイアウトは 実際には正確なものではありません セパレータは セルの主要なコンテンツと ラインアップするようにできており この例は 画像ビューではなく どちらかというと セルのラベルになります リーディングサイドでは セパレータは インセットされ このラベルの端と一致するようにできています “SEPARATOR INSET” このようにです “PRIMARY CONTENT” UITableViewでは セパレータインセットと呼ばれる ポイントベース値を提供することで行います このAPIを導入した時には これはとても簡単でした というのも ラベルのXオフセットをマニュアルで 計算するという方法がすでにあったので 同じ方法を使って 同じ値で セパレータ インセットの構成もできたからです しかしながら この最新の自動レイアウトの時代では 皆さんには 安全なエリアインセットや レイアウトマージン ダイナミック フォントサイズやSFシンボルがありますので そう簡単にはいきません 今日の環境は 高度にダイナミックなので これら値は どの瞬間にも変わりえるのです ダイナミックフォントやSFシンボル ユーザーのフォントサイズの好みにより 画像のサイズも変わりますし ラベルの位置も変えることができます 予め ラベルがどのように表示されるかを すべて予想することは非常に難しいのです リストセルで セパレータレイアウトガイドと 呼んでいる 新しいコンセプトを導入していてます このレイアウトガイドは UIKitにある 既存のレイアウトガイドとは 挙動が違います コンテンツをこのレイアウトガイドに 嵌めるのではなく このレイアウトガイドをコンテンツに嵌めるので 今までのレイアウトガイドを操作するときに 慣れている操作とは逆になります このセパレータガイドを設定する最も簡単な 方法は セルのレイアウトを最初に構成し 意図通りの外観のセルができたなら 追加の制限を一つ 加えます セパレータレイアウトガイドの リーディングアンカーを ラベルリーディングアンカーへ繋ぐか または セル内の 主要コンテンツへと繋げます リストセルとリストセクションは セルの主要コンテンツに対し セパレータが自動で一致するようにします
ここで肝心なのは システム提供のコンテンツ コンフィギュレーションを使っている場合 これは自動で行われますので ここは何もしなくて結構です でも カスタムセルレイアウトを 使用している場合は セパレータが正確な位置にあることを 担保する簡単な方法なのです
“SWIPE ACTIONS” では スワイプアクションについて お話しましょう
UITableViewとは対照的に スワイプアクションは 今では リストセルのフィーチャーです セルのコンテンツと 構成します セルの画像ビューまたはラベルを どこで構成しようと リーディングスワイプアクション または トレーリングスワイプアクションを設定できます
これにはセルとレイアウト間の 通信が必要なので スワイプアクションは セルがリスト構成を使用して構成された セクション内にレンダリングされる 場合にのみサポートされます
UITableViewにあったような スワイプアクション APIのダイナミックな特徴が必要な場合は スワイプが開始される 直前に スワイプ コンフィギュレーションだけを作成したり リーディングまたはトレーリング スワイプ アクションコンフィギュレーション ゲッターを オーバーライドしてから コンフィギュレーションをそこに作成します ユーザーが 実際このセルを スワイプしようとしたときに ゲッターだけを 呼び出すようにしなくてはなりません
ここで一つ 警告です スワイプアクションのアクションハンドラで 構成しているセルのインデックスパスは 絶対にキャプチャーしないようにしてください このインデックスパスは 安定した識別子ではありません その上のコンテンツを 挿入や削除するときに 必ずこのセルのインデックスパスは変化します そして このセルは 必ずしも再読み込みされないのです スワイプアクションのトリガーをかけたとき 皆さんが格納されたインデックスパスを使い セルのデータモデルを呼び出そうとする場合は 実際は それ以外のセルのデータを 操作しているのかもしれません これは 削除アクションをする時 とても危険です というのも 間違ったデータを 削除しているかもしれないからです その代わり 直接にデータモデルをキャプチャするか このセルのコンテンツを特定するのに使う 安定した識別子をキャプチャすることです 差分最適データソースと その安定したアイテム識別子 それとiOS 14の新規のセル登録タイプが これには適しているでしょう
次は アクセサリについてお話します “ACCESSORIES” UITableViewでは APIのアクセサリは かなり限られていました アクセサリタイプとアクセサリビューへ アクセスはできましたが これらは相互排他的で 該当セルの トレーリングサイドだけに関連していました
リストセルは 多岐にわたる 新しいアクセサリタイプを提供しており セルのトレーリングとリーディングの 両サイドにアクセサリの構成もできますし 同じサイドに 複数のアクセサリを 構成することも 可能です
更に UITableViewセルのアクセサリが どちらかというとデコレーションビュー のような場合でも リストセルの中では機能を有効化できます
例えば 再オーダーアクセサリを入れた セルを構成する場合は 再オーダーモードに自動で コレクションビューを入れます これは ユーザーが このアクセサリを タップした時には 必要な再オーダーコールバックを 実装するだろうと想定して作りました “REORDER” “DELETE” もう一つの例は 削除アクセサリーですが 以前は 削除編集コントロールとして 知られていました ユーザーが このアクセサリを タップすると リストセルは 自動でセルで構成されている トレーリング スワイプアクションを表示します
そして ここに全く新規のアクセサリがあります これは アウトライン開示アクセサリです このアクセサリをユーザーが タップすると セルは自動で データソースと通信し このセルの下層を拡張または畳み込みます これは 新しいセクションスナップショット APIの使用が必要ですが これについては“Advances in Diffable Data Source.”をご参照ください
ではここで APIの動きを見てみましょう 皆さんのセルのアクセサリを構成するために リストセルにある たった一つのアクセサリプロパティを UIセルアクセサリのエリアへ 設定するだけでできます この例として 開示インジケータと 削除 アクセサリのあるセルを構成してみましょう システムは 開示インジケータは 常にセルの トレーリングサイドにあるべきだと認識しており 反対に 削除アクセサリは リーディング サイドにあると認識しています そして UIKitは 自動でアクセサリを 正しい順序に整理し 適切な側に表示します
更に システムは 開示インジケータが 常に可視状態で あるべきであることも認識しており また 削除アクセサリはコレクション ビューが モードを編集時に以外で 可視化してはいけないということを 認識しています 従って UIKitは 編集モードに入る またはそこから出るとき 自動で 削除アクセサリのイン またはアウトをアニメ化します
私たちは これらシステムデフォルトを 多く提供していますが もちろん そのほとんどを カスタム化することができます 例えば 編集モードではないときだけ 開示インジケータを可視化したいとき 簡単です 表示パラメータを whenNotEditingに設定してください これは 超宣言型APIですので UIKitが 皆さんの代わりに すべての状態を管理します ご覧になったように リストは 高度にカスタム化されたレイアウトですので モジュール化されており フレキシブルです 適用は非常に簡単です さて サンプルコードを見てみて いろいろとやってみましょう ここでは 多くの発見があります そして この新しいAPIに慣れたら ご自身のアプリケーションのレイアウト どこが強化できるか 考えてみてください 既存のテーブルビューのどこを置き換え カスタム構成レイアウトと組み合わせる リストの柔軟性の利用を考えてみてください もちろん UICollectionViewについて 他のビデオも たくさんあるので チェックしてみてください iOS 14のコレクションビューには 驚くような 素敵なフィーチャーが盛りだくさんです
ご覧いただきありがとうございました
-
-
3:47 - Simple Setup
// Simple setup let configuration = UICollectionLayoutListConfiguration(appearance: .insetGrouped) let layout = UICollectionViewCompositionalLayout.list(using: configuration)
-
4:25 - Per-Section Setup
// Per section setup let configuration = UICollectionLayoutListConfiguration(appearance: .insetGrouped) let section = NSCollectionLayoutSection.list(using: configuration, layoutEnvironment: layoutEnvironment)
-
4:40 - Per-Section Setup full
// Per section setup let layout = UICollectionViewCompositionalLayout() { [weak self] sectionIndex, layoutEnvironment in guard let self = self else { return nil } // @todo: add custom layout sections for various sections let configuration = UICollectionLayoutListConfiguration(appearance: .insetGrouped) let section = NSCollectionLayoutSection.list(using: configuration, layoutEnvironment: layoutEnvironment) return section }
-
5:49 - Header Mode Supplementary
var configuration = UICollectionLayoutListConfiguration(appearance: .insetGrouped) configuration.headerMode = .supplementary let layout = UICollectionViewCompositionalLayout.list(using: configuration) dataSource.supplementaryViewProvider = { (collectionView, elementKind, indexPath) in if elementKind == UICollectionView.elementKindSectionHeader { return collectionView.dequeueConfiguredReusableSupplementary(using: header, for: indexPath) } else { return nil } }
-
6:51 - Header Mode Supplementary Optional Header
let layout = UICollectionViewCompositionalLayout() { [weak self] sectionIndex, layoutEnvironment in guard let self = self else { return nil } // check if this section should show a header, e.g. by implementing a shouldShowHeader(for:) method. let sectionHasHeader = self.shouldShowHeader(for: sectionIndex) let configuration = UICollectionLayoutListConfiguration(appearance: .insetGrouped) configuration.headerMode = sectionHasHeader ? .supplementary : .none let section = NSCollectionLayoutSection.list(using: configuration, layoutEnvironment: layoutEnvironment) return section }
-
7:07 - Header Mode First Item In Section
var configuration = UICollectionLayoutListConfiguration(appearance: .insetGrouped) configuration.headerMode = .firstItemInSection let layout = UICollectionViewCompositionalLayout.list(using: configuration)
-
11:40 - Swipe Actions
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Model> { (cell, indexPath, item) in // @todo configure the cell's content let markFavorite = UIContextualAction(style: .normal, title: "Mark as Favorite") { [weak self] (_, _, completion) in guard let self = self else { return } // trigger the action with a reference to the model self.markItemAsFavorite(with: item.identifier) completion(true) } cell.leadingSwipeActionsConfiguration = UISwipeActionsConfiguration(actions: [markFavorite]) }
-
14:55 - Accessories
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, String> { (cell, indexPath, item) in // @todo configure the cell's content cell.accessories = [ .disclosureIndicator(), .delete() ] }
-
15:51 - Accessories w/ Parameters
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, String> { (cell, indexPath, item) in // @todo configure the cell's content cell.accessories = [ .disclosureIndicator(displayed: .whenNotEditing), .delete() ] }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。