ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
iPadOSのタブとサイドバーの利用体験を向上
iPadOS 18では、タブバーとサイドバーのどちらを使用するかをユーザーが柔軟に選択できる新しいナビゲーションシステムが導入されます。デザインが一新されたタブバーでは、コンテンツやその他の機能により広いスペースが割り当てられています。SwiftUIとUIKitを使用して、タブの追加、削除、並べ替えなど、カスタマイズのための機能を実装し、アプリの操作性を高める方法を確認しましょう。
関連する章
- 0:00 - Introduction
- 0:52 - Tab bar and sidebar refresh
- 3:56 - Tab bar and sidebar features
- 4:28 - Tab bar SwiftUI updates
- 5:00 - Tab bar UIKit updates
- 5:58 - Search tab
- 6:41 - Enable sidebar with TabView in SwiftUI
- 7:16 - Enable sidebar with UITabBarController in UIKit
- 7:46 - Sidebar actions
- 8:13 - Drop destinations on Tabs in SwiftUI
- 8:25 - Drop destinations on UITabs in UIKit
- 9:15 - User customization
- 10:45 - Enable customization in SwiftUI
- 12:38 - Enable customization in UIKit
- 13:52 - Platform considerations
リソース
- Destination Video
- Elevating your iPad app with a tab bar and sidebar
- Enhancing your app’s content with tab navigation
- Forum: UI Frameworks
関連ビデオ
WWDC22
WWDC20
-
ダウンロード
「Elevate your tab and sidebar experience in iPadOS」へようこそ UIKitエンジニアのAndyです このセッションでは タブバーとサイドバーの 機能強化について説明します この機能強化は アプリの利用体験を向上させ アプリ内でコンテンツを 際立たせる上で役立ちます タブバーは 登場以来 iPhoneとiPadの 主要なナビゲーションのパターンです タブにより アプリのコンテンツを 複数のセクションに分類できます
タブバーを使うことで それぞれのタブ内の状態を維持したまま タブ間を素早く切り替えて表示できます 例えば 時計アプリでは タブバーに4種類のタブがあります 世界時計 アラーム ストップウォッチ そしてタイマーです
iPadOS 18では タブバーが一新され 新しいコンパクトな外観になりました 使用されていない縦方向 および横方向のスペースを減らし より多くのコンテンツを前面に出しています
バーがアプリの上部に配置され ほかのナビゲーションコントロールと 近くなったことで アクセスしやすくなっています また 上部のバーと 同じ領域に表示されるため アプリのコンテンツの 表示領域がさらに広がります
タブは iPhoneとiPadの間で 統一されている必要があります それによりユーザーは 使用する デバイスを問わず簡単に操作できます タブは増やしすぎないようにしましょう 選択肢が多すぎると アプリ内の情報を見つけにくくなります
タブバーと同様に サイドバーも アプリ内のナビゲーションに役立ちます サイドバーにより トップレベルの領域に すばやくアクセスできます フォルダやプレイリストなどコンテンツの トップレベルのコレクションを 目立つ場所にまとめて表示して 効率的なナビゲーションを実現できます iPadOS 17以前のサイドバーでは Split Viewが使用され 先頭の列が アウトラインビューになっていました
iPadOS 18では 新機能として オプションでタブバーを サイドバーとして表示できるほか 各種の機能強化により これまで以上に優れたサイドバーを 実現できます
サイドバーが非表示になると タブバーに戻るアニメーションが表示され タブで表示されているコンテンツに フォーカスが戻ります
再度サイドバーを開くことなく タブバーでナビゲーション操作ができます
タブバーには アプリのトップレベルのセクションを表示し サイドバーには 同じ階層構造のもとで より多くのセクションを表示できます タブバーとサイドバーの採用は 詳細な階層構造を持つ コンテンツ重視のアプリに適しています タブバーによるナビゲーションの ベストプラクティスは 「Explore navigation design on iOS」を ご確認ください サイドバーの詳細は「Designed for iPad」を ご覧ください
コンテンツが充実したアプリには パワフルさに加え パーソナルな 操作性も求められます 新しいサイドバーは カスタマイズ機能をサポートしており 個々のタブの 表示と非表示の切り替えや 並べ替えができます
タブバーでは ドラッグ&ドロップで お気に入りのタブを追加できます これにより 画面の表示を 簡単にパーソナライズできます
既存のサイドバーに タブバーを導入することで 両方の長所を組み合わせて 新しい方法でアプリのカスタマイズや パーソナライズを実現できます まず 新しいタブバーとサイドバーの機能と 導入時の考慮事項について説明します
次に アプリを より高度にパーソナライズするための ユーザーによるカスタマイズの サポートについて説明します
最後に 各種プラットフォームで これらの機能がどのように動作するか説明し また マルチプラットフォーム対応のアプリを 構築する際の考慮事項をご紹介します
まずは タブバーとサイドバーの説明です iPadOS 18 SDKでコンパイルすると 既存のタブバーを備えたアプリは コードの 変更なしで新しい外観に更新されます 更新された外観では タブバーとナビゲーションバーが 同じセーフエリアに表示され 画面のまとまりが向上しています
ナビゲーションバーのツールバー項目を タブバーと並べて表示するスペースが 十分にない場合 ツールバー項目は 自動的にオーバーフローに移動されます
iOS 18の新機能として SwiftUIのTabViewには 新しい構文が導入されており ビルド時によくあるエラーの 検出が向上しています タイトル 画像 コンテンツビューを指定して Tab構造体を宣言するようになりました
必要に応じて Tabにselection値を含めることで プログラムによる選択も実装できます この新しい構文では すべてのTabが同じselectionの型を持ち TabView自体の型とも一致しています
iOS 18の新機能として UIKitにUITabBarControllerの アプリ階層の記述を改善する 新しいAPIが追加されました
アプリのトップレベルのセクションごとに UITabを作成し tabBarControllerの tabsプロパティに割り当てます UITabインスタンスに加えられた変更は タブの表示箇所に 即座に反映されます
タブバーには塗りつぶしグリフが サイドバーにはアウトライングリフが 適しています タブにシンボル画像を使用する場合は アウトラインのバリアントを使用します
画像がタブバーに表示される場合 システムにより自動的に 塗りつぶしのバリアントが選択されます 例えばMusicアプリでは に square.grid.2x2 のシンボル画像を使用していますが これはアウトライン化されたグリフです タブバーでは 別の画像を指定しなければ 塗りつぶしのバリアントが表示されます
検索はどのアプリにも共通の機能であり 虫眼鏡のシンボルですぐにわかります
SwiftUIのsearch roleタブ またはUIKitのUISearchTabを 使用すると システムにより タブのデフォルトのタイトルおよび画像や ピンで固定された配置が設定されます ピンで固定された配置では タブバーの末尾に そのタブが必ず表示されます
iPadアプリに詳細な階層構造があり コンテンツのコレクションが 多数表示される場合 サイドバーが適しています
アプリで 新しいタブとUIタブのAPIを使用すると タブバーとサイドバーの両方に対応した アプリの構造を構築できます
SwiftUIのTabViewで サイドバーを有効にするには まず tabViewStyleに sidebarAdaptableを設定します
次に TabSectionを使用して サイドバー内のグループを作成します
タブは 宣言された順序で タブバーに表示されます サイドバーでは 個別のタブの後にセクションが並びます この例の場合 サイドバーでは 2つのTabSectionの前に 検索が表示されます
UIKitで UITabBar Controllerを使用してサイドバーを 有効にするには tabBarControllerのmodeに tabSidebarを設定します TabSectionsと似ていますが こちらでは UITabGroupを使用して 1つのグループに属する 子タブのコレクションを指定します
動的コンテンツのあるグループは グループの子を直接変更すると更新されます
また サイドバーのセクションに アクションを追加すると よく使う機能に 迅速にアクセスできるようになります この例ではポッドキャストの 新規ステーションの作成を追加しています
タブはドロップ先としても使用できます コレクションに写真を追加する場合などに ドラッグ&ドロップで サイドバーやタブバーのタブに 直接追加することができます
SwiftUIで タブへの ドロップをサポートするには Tabに対して レシーバーの型を指定して dropDestination モディファイアを使います
UIKitで UITabへの ドロップをサポートするには UITabBarController デリゲートの2つのメソッドを実装します まず タブへのドロップに対して 有効な処理が operationForAccepting ItemsFromの DropSessionから 返されるようにします
次に データを受信するために acceptItemsFromの dropSessionから ドロップセッションのデータを読み込みます アクションやドロップ先以外にも 様々な新しいAPIを使用して サイドバーをカスタマイズできます サイドバーのヘッダとフッタを カスタマイズできるほか タブに スワイプアクションや コンテキストメニューも追加できます また タブから ポップオーバーが出るようにして タブの場所に関わらず タブと一緒に表示するようにできます タブでアプリを詳細に構成するのは 最初のステップに過ぎません 次は ユーザーによるアプリの パーソナライズを可能にする カスタマイズ機能の追加方法を説明します
カスタマイズを有効にすると ユーザーが 自身に固有のニーズに基づき サイドバーを構成できるようになります 重要でないタブの非表示化や サイドバーの グループの配置の変更などがその例です 順番や表示/非表示に関する カスタマイズは 自動的に保持されます
タブバーのカスタマイズは iPadOS 16で導入された ツールバーのカスタマイズ機能に似ています
タブバーの項目は ドラッグ&ドロップでカスタマイズできます サイドバーから追加するか タブバーの外にドラッグして削除します
タブには カスタマイズや 表示/非表示を設定する際に参照できる 推奨の配置があります
タブバーには3つのセクションがあります
固定のセクションは アプリのユーザーが よくアクセスする重要な領域に使用します ほかのアイテムより前に表示され カスタマイズすることはできません
カスタマイズ可能なセクションの項目は 並べ替えできます サイドバーからドラッグ&ドロップで 項目を追加することもできます
検索のように ピンで固定されたセクションは 常にタブバーの末尾に表示されます
サイドバーのみの配置を使用すると タブをタブバーに追加することを禁止して サイドバーからのみアクセス可能に することができます
SwiftUIで ユーザーによる TabViewのカスタマイズを可能にするには まず TabViewCustomizationを TabViewにアタッチします これにより TabView内のタブで様々な カスタマイズ機能が使用可能になります
ほかのUIについても サイドバーの カスタマイズを反映させる必要がある場合は TabViewCustomizationから 読み取ってカスタマイズされた データを追跡させます
カスタマイズの内容を保持するために AppStorageにIDを指定して TabViewCustomizationに追加します
次に customizationIDを関連づけて そのタブをカスタマイズの対象にします
これでカスタマイズが有効になったので やといった アプリ内で特に重要なタブの表示を固定し 常に表示されるようにしたいと思います
個別のタブについて カスタマイズを無効にするには customizationBehavior モディファイアを使用します このモディファイアを使用すると サイドバーおよびタブバーにおける タブの動作を制御できます タブは このアプリの機能において重要です そのため サイドバーとタブバーの両方で カスタマイズを無効にします
カスタマイズできないタブには customizationIDは必要ありません
同様に タブを非表示にすることもでき アプリ内のどの領域を デフォルト表示するかを柔軟に指定できます defaultVisibility モディファイアで タブを サイドバーや タブバーで非表示にできます
これで と のカスタマイズが 無効になったので アプリにおける 重要なタブとカスタマイズ可能なタブが 明確に区別されました
UIKitで タブの カスタマイズを有効にする場合 allowsHidingにtrueを設定すると 重要でないタブを非表示にできます
現在の表示/非表示の設定は
UITabのisHiddenプロパティで 決まります
タブがtabBarControllerに 割り当てられると 保存されているカスタマイズ内容が 適用されます
preferredPlacementプロパティを 使用して タブのカスタマイズの動作と タブバーにおける表示を制御できます
グループ内でタブを 並べ替えられるようにするには allowsReorderingを trueに設定します カスタマイズ後の順番を決めるのは displayOrderIdentifiersプロパティです
カスタマイズが完了すると UIKitは これら2つの UITabBarControllerDelegateメソッドを 呼び出して カスタマイズによる タブの表示と順番の 変更をユーザーに通知します
カスタマイズにより ユーザーは お気に入りのコンテンツへの ショートカットを簡単に作成し サイドバーとタブバーを自分のニーズに 合わせて調整できます これらのAPIは 各種Appleプラットフォーム対応の タブビューアプリの構築を容易にします 次に プラットフォームに関する考慮事項と 各プラットフォームで優れた体験を 実現するための調整について説明します macOS Sequoiaでは TabViewやTabBarControllerが サイドバーをサポートしている場合 標準のMacのサイドバーの 外観が適用されます サイドバーのタブは iPadの場合と同様に ドラッグ&ドロップで並べ替えできます
visionOS 2では タブバーは ルートタブ用のウインドウの 先頭部分にあるオーナメントに表示されます 新しいタブとUIタブのAPIを使用すると シンボルがタブバーに表示される場合は システムにより自動的に 塗りつぶしのバリアントが選択されます iOSと同様です
TabSectionまたは UITabGroupを使用すると サイドバーも追加され グループ内のセカンダリナビゲーション用の グループのコンテンツと 並んで表示されます
tvOS 18では SwiftUIアプリで TabViewとTabSection APIを使用して 折りたたみ可能な 新しいサイドバーを導入できます
タブとUIタブのAPIにより Appleプラットフォーム全体で 操作しやすくコンテンツが豊富で高品質な アプリを 従来以上に簡単に構築できます 次のステップとして 新しいタブバーを取り入れて 素晴らしいアプリを構築しましょう 新しいサイドバーにより アプリがどう向上するか試してみましょう アプリの高度なパーソナライズを可能にする ユーザーによるカスタマイズの機能を 導入しましょう ご視聴ありがとうございました タブとスペースのどちらが好みかを ぜひコメントをお寄せください
-
-
4:27 - TabView updates in SwiftUI
TabView { Tab("Watch Now", systemImage: "play") { WatchNowView() } Tab("Library", systemImage: "books.vertical") { LibraryView() } // ... }
-
4:58 - UITabBarController updates in UIKIt
tabBarController.tabs = [ UITab(title: "Watch Now", image: UIImage(systemName: "play"), identifier: "Tabs.watchNow") { _ in WatchNowViewController() }, UITab(title: "Library", image: UIImage(systemName: "books.vertical"), identifier: "Tabs.library") { _ in LibraryViewController() }, // ... ]
-
5:58 - Search tab
// SwiftUI Tab(role: .search) { SearchView() } // UIKit let searchTab = UISearchTab { SearchViewController() }
-
6:41 - Adding a sidebar in SwiftUI
TabView { Tab("Watch Now", systemImage: "play") { // ... } Tab("Library", systemImage: "books.vertical") { // ... } // ... TabSection("Collections") { Tab("Cinematic Shots", systemImage: "list.and.film") { // ... } Tab("Forest Life", systemImage: "list.and.film") { // ... } // ... } TabSection("Animations") { // ... } Tab(role: .search) { // ... } } .tabViewStyle(.sidebarAdaptable)
-
7:16 - Adding a sidebar in UIKit
let collectionsGroup = UITabGroup( title: "Collections", image: UIImage(systemName: "folder"), identifier: "Tabs.CollectionsGroup" children: self.collectionsTabs()) { _ in // ... } tabBarController.mode = .tabSidebar tabBarController.tabs = [ UITab(title: "Watch Now", ...) { _ in // ... }, UITab(title: "Library", ...) { _ in // ... }, // ... collectionsGroup, UITabGroup(title: "Animations", ...) { _ in // ... }, UISearchTab { _ in // ... }, ]
-
7:35 - Updating a tab group in UIKit
let collectionsGroup = UITabGroup( title: "Collections", image: UIImage(systemName: "folder"), identifier: "Tabs.CollectionsGroup" children: self.collectionsTabs()) { _ in // ... } let newCollection = UITab(...) collectionsGroup.children.append(newCollection)
-
7:45 - Sidebar actions
TabSection(...) { // ... } .sectionActions { Button("New Station", ...) { // action } } // UIKit let tabGroup = UITabGroup(...) tabGroup.sidebarActions = [ UIAction(title: "New Station", ...) { _ in // action }, ]
-
8:12 - Drop destinations in SwiftUI
Tab(collection.name, image: collection.image) { CollectionDetailView(collection) } .dropDestination(for: Photo.self) { photos in // Add 'photos' to the specified collection }
-
8:24 - Drop destinations in UIKit
func tabBarController( _ tabBarController: UITabBarController, tab: UITab, operationForAcceptingItemsFrom dropSession: any UIDropSession ) -> UIDropOperation { session.canLoadObjects(ofClass: Photo.self) ? .copy : .cancel } func tabBarController( _ tabBarController: UITabBarController, tab: UITab, acceptItemsFrom dropSession: any UIDropSession) { session.loadObjects(ofClass: Photo.self) { photos in // Add 'photos' to the specified collection } }
-
10:45 - TabView customization in SwiftUI
@AppStorage("MyTabViewCustomization") private var customization: TabViewCustomization TabView { Tab("Watch Now", systemImage: "play", value: .watchNow) { // ... } .customizationID("Tab.watchNow") // ... TabSection("Collections") { ForEach(MyCollectionsTab.allCases) { tab in Tab(...) { // ... } .customizationID(tab.customizationID) } } .customizationID("Tab.collections") // ... } .tabViewCustomization($customization)
-
11:40 - Customization behavior and visibility in SwiftUI
Tab("Watch Now", systemImage: "play", value: .watchNow) { // ... } .customizationBehavior(.disabled, for: .sidebar, .tabBar) Tab("Optional Tab", ...) { // ... } .customizationID("Tab.example.optional") .defaultVisibility(.hidden, for: .tabBar)
-
12:38 - Tab customization in UIKit
let myTab = UITab(...) myTab.allowsHiding = true print(myTab.isHidden) // .default, .optional, .movable, .pinned, .fixed, .sidebarOnly myTab.preferredPlacement = .fixed let myTabGroup = UITabGroup(...) myTabGroup.allowsReordering = true myTabGroup.displayOrderIdentifiers = [...]
-
12:39 - Observing customization changes in UIKit
func tabBarController(_ tabBarController: UITabBarController, visibilityDidChangeFor tabs: [UITab]) { // Read 'tab.isHidden' for the updated visibility. } func tabBarController(_ tabBarController: UITabBarController, displayOrderDidChangeFor group: UITabGroup) { // Read 'group.displayOrderIdentifiers' for the updated order. }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。