ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
デスクトップクラスのiPadの紹介
デスクトップクラスの機能をご利用のiPad Appに追加する方法を紹介します。また、UINavigationBarの最新情報も詳しく解説しますので、ご利用のApp機能がわかりやすくなり、カスタマイズもできるようになります。さらに、UIKitの最新情報により、App内でのコンテンツ検索がどう簡単かつ迅速になったのかご覧ください。最後に、最新情報をいくつか紹介して、Mac Catalystにより、iPad Appのデスクトップへの導入が従来に比べどう簡単になったのかを解説します。
リソース
- Building a desktop-class iPad app
- centerItemGroups
- searchSuggestions
- Supporting desktop-class features in your iPad app
- titleMenuProvider
- UIDocumentProperties
- UINavigationItem.ItemStyle
- UINavigationItemRenameDelegate
関連ビデオ
WWDC23
WWDC22
-
ダウンロード
このセッションでは 私 David Duncan が デスクトップクラスのiPadをご紹介します iOS 16 は 優れた App を 設計するツールを進歩させ 多くの優れたツールを最前線にもたらし あらゆるハードウェアを 活用できるようにします UIKit に そのために多くの ツールを追加しています UINavigationBar の更新により 画面をより有効活用し すべてのプラットフォームで 優れた体験が構築できます
新しい検索と置換の UI は 組み込みのビューで有効にでき カスタムビューにも追加できます 編集メニューを一新して メニューシステムと統合した インタラクションベースの 新しいAPIを追加しました コレクションビューの改良で ユーザーにコンテンツを選び 行動させるインターフェースも より簡単に構築できます
編集メニューなど詳細は 「デスクトップクラスの 編集操作を取り入れる」を 機能の連携については 「デスクトップクラスの iPad Appを構築する」をご覧ください
ここでは iOS 16 向けの App の設計方法に影響する ナビゲーションの変更についてお話しします
まず 発見しやすいインターフェイスを 構築する新機能 次に ドキュメントベースの App で 特に効果的な機能 最後に 体験を加速 洗練する 検索機能のアップデートです
UINavigationBar は iOS 上で 様々な用途で使用されており iOS 16 では 最適化された 新しい UI を提供しています UINavigationItem に style プロパティを追加し ナビゲータ ブラウザ エディタから選択します それぞれのスタイルを見ていきましょう デフォルトのナビゲータは 従来の UINavigationBar と同じ動作です タイトルを中央に配置し
先頭と末尾にバーボタン項目があり スタックがあると戻るボタンを表示します ブラウザはFilesやSafariのように 履歴が重要なインターフェースに 最適化するようにコンテストを並べ替えます
タイトルは先頭に移動します
エディタースタイルはドキュメントの編集を 主な機能とする場合に最適です タイトルは先頭揃えで表示されます エディターの UI は ドキュメント選択後の ビューとなることが多いので その UI に戻るボタンを提示します
ブラウザ エディタともに
バーの中央に大きなスペースがあり この領域に追加コントロールを配置できます
センターアイテムは画面領域を より有効活用するための変更があり UIBarButtonItemGroup のサポートや カスタマイズのサポート オーバーフローが含まれます
オーバーフロー対応は すべてのモードで利用可能で ナビゲータースタイルで センターアイテムにも対応可能になります
引き続き個々のコントロールは UIBarButtonItems として設定されますが UIBarButtonItemGroups として整理されます スペースが限られている場合 より密な表現ができます この例ではバーに5つのアイテムがあり 4つのグループから構成されています
最初のグループには バーボタン項目が1つ含まれており UIBarButtonItem のコンビニエンスメソッド creatingFixedGroup() で作成しています
1つ以上の項目を持つ 固定グループが必要な場合は UIBarButtonItemGroup() が使用できます
固定グループは常にバーの最初に表示され カスタマイズで削除や移動はできません ドローインググループは1つのアイテムを含むので creatingMovableGroup (customizationIdentifier) というAPIを使用します 固定グループと同様に 移動可能グループも 削除はできませんが 移動は可能です
そのため 位置を追跡して保存できるように customizationIdentifier が必要です 複数の項目を持つグループが必要な場合は UIBarButtonItemGroup メソッドを使用します
図形グループには複数アイテムが含まれるため UIBarButtonItemGroup APIを 使用してグループを作成します
このグループはバー内で移動可能で かつ取り外し可能である必要があるので オプションのグループとして作成されます
このグループでは representativeItem を指定し 必要に応じてグループを折りたたんで スペースを確保できるようにします
representativeItem は動作を指定しないので グループ内のアイテムを選べる メニューが合成できます
カスタマイズ UI を起動すると グループの作成方法に基づいて 指定されたルールを自動的に適用します 固定および可動グループは バー内に留まりますが オプショングループは 自由に追加や削除できます
UIKit はより多くの機能をバーに置くために グループを折りたたもうとしますが それでもスペースが足りない場合 余分な項目はオーバーフローに移動します オーバーフローメニューには バーに収まらなかったカスタマイズ項目や バーをカスタマイズするための オプションが含まれています UIKit は各バーボタンの項目に対して
デフォルトのメニュー要素を構成しますが menuRepresentation をカスタマイズできます 最後にこの例ではカスタマイズを有効にして centerItemGroups を追加しています
UINavigationItem.customizationIdentifier を 設定するとカスタマイズが有効になります
customizationIdentifier には App 内の他の IDと重複しない文字列を選びます
カスタマイズをこの識別子に 基づき保存・復元します
次に centerItemGroups 自体を用意します 最初の4つのグループは既に説明したとおりです
format グループは デフォルトのカスタマイズに無いので このコードではパラメータのデフォルト値 isInDefaultCustomization を上書きして 除外しています UINavigationItem.customizationIdentifier を設定しなくても centerItemGroups は使用できますが カスタマイズは使えなくなります Mac Catalyst では UINavigationBar は内容を NSToolbar に変換します 先頭 中央 末尾のアイテムグループは 順番に追加され 中央のアイテムグループの カスタマイズプロパティは NSToolbar カスタマイズを 使用するときに尊重されます
他のプロパティと同様に 期待される NSToolbar の すべての動作が利用可能です
Mac 用に最適化すると これらすべてがデフォルトで行われます 次にドキュメントを扱う際に力を発揮する インタラクションに焦点を当てましょう UINavigationBar はタイトルビューへの メニューの追加に対応し コンテンツ全体を操作する動作を 追加する場所を提供します さらにこのメニューから シェアシートとドラッグ&ドロップを サポートできます まずメニューの項目自体に着目します デフォルトのタイトルメニューには 複製 移動 名称変更 プリント 書き出す の5つのコマンドが用意され レスポンダチェーン内の 特定のメソッドに基づき フィルタリングされます UINavigationBar は名称変更に 固有のサポートを持っており renameDelegate も含まれます
タイトルメニューを有効にするには titleMenuProvider を設定します 最終的に表示されるメニューを返す クロージャです
このクロージャには提案された要素の 配列が渡されます これにフィルターをかけたり 独自の項目を追加したりできます この例では メニューに1つの アクションを追加しています 最後に 構成された UIMenu を返します
タイトルメニューはアクティビティ ビューコントローラーによる共有や ドラッグ&ドロップもサポートできます
有効にするにはドキュメントを表す UIDocumentPropertiesの インスタンスを提供します
UIDocumentProperties は プレビューを含む ドキュメントに関するメタデータです この例では UIKit が必要なメタデータを 自動的に取得できるよう URL付きのものを作成しています
追加機能を有効にするためドキュメントを表す NSItemProvider を作成します
ドラッグ&ドロップを有効にするには dragItemsProvider を設定します このクロージャは UIDragSession を通して UIDragItems 配列を返します この例ではドキュメントを表す 1つのアイテムを返します
activityViewControllerProvider を設定すると 共有が可能になります このクロージャは UIActivityViewController を設定し返します
最後にこのオブジェクトを UINavigationItem.documentProperties に 設定すると タイトルがタップされた時に 他の titleMenu アイテムと一緒に ヘッダーを表示します
Mac Catalyst では titleMenuProvider に渡される推奨項目は すでに File メニューに存在しています タイトルメニューに追加する項目は 他の方法で利用可能にする必要があります
UIMenuBuilder API でこれらの項目の追加や 既存の項目のフィルタリングができます
ドキュメントプロパティを指定すると UIKit は URL を使用して macOS のプロキシアイコンを管理します
windowScene の representedURL を 手動で設定した場合は UIKit の管理よりも優先されます
UIKit は名称変更を有効にする 2つのメカニズムを提供しています UINavigationItem.renameDelegate の設定で インラインでのリネームや タイトル編集用の UI を提供し
完了すると 結果の名前が デリゲートに渡されます
UIResponder.rename(_:) を実装して 好みのUIを提供して 名称変更を完全にコントロールできます
UINavigationBar は iOS ではタイトルビューの中で 直接名称変更の UI を提供します macOS ではナビゲーションバーが NSToolbar でホストされると ウィンドウのタイトルで リネームの UI が提供されます インラインの名称変更を実装するには UINavigationItemRenameDelegate に準拠し ナビゲーションアイテムの renameDelegate に設定します navigationItem(_:didEndRenamingWith:) は ユーザーに承認されたタイトルを 受け取るために使用します
ファイルベースの App の場合 UIDocumentBrowserViewController が 名称変更のAPIを提供します
検索は多くのユーザーが最も重要な データを見つける方法であり iOS 16 の進化により 優れた検索体験の提供が容易になります まず検索が iPadOS ではナビゲーションバーに macOS ではツールバーに配置されることで スペースを取らないようになっています iPadOS では UINavigationItem .preferredSearchBarPlacement で 以前の動作に戻すことができます また検索バーをボタンに折りたたむことで 他の操作スペースが確保できます 検索を有効にすると検索候補が表示され 更新中の検索クエリと一緒に更新ができ ユーザーの検索を支援できます 次に 検索候補を設定するために 必要なコードを説明します
検索サジェストの管理では UISearchResultsUpdating に準拠し searchController の searchResultsUpdater を設定します クエリの変更に応じたサジェストの更新や 検索サジェストに対する行動が起こせます
クエリを変更すると updateSearchResults(for:) が呼ばれ 検索候補が更新できます
どのような候補を提案をするかは あなた次第です 空の配列を設定すると サジェスト UI を消去します
サジェスト内容の指定のために UISearchSuggestionItem があり
サジェストの選択に応答するには updateSearchResult(for:selecting:) を実装します このメソッドは選択された 検索候補を受け取るので それに対して適切に対応します この例では 現在のクエリを 検索候補で指定されたクエリに置き換えて 検索を更新しています UISearchTextField にも searchSuggestions があり そのクラスを単独で使用したい場合でも 検索サジェストを実装することが可能です UISearchController の場合は そのプロパティを使用します
iOS 16では UIKit が新しい API を提供し ユーザーにさらなる生産性を 提供できるようになりました センターアイテムやタイトルメニューで 高度な機能がより発見しやすくなります
ナビゲーションバーから 直接ドラッグ&ドロップや共有ができ ドキュメントのサポートが向上します 検索候補を表示することで 検索をより簡単かつ迅速にし ほぼゼロの労力ですぐに素晴らしい Mac でのエクスペリエンスが 手にできるようになります ありがとうございました 皆様がデスクトップクラスのAppを どのように充実させるのか楽しみです
-
-
4:27 - Creating a fixed UIBarButtonItemGroup from a single UIBarButtonItem
let insertGroup = UIBarButtonItem(title: "Insert", image: UIImage(systemName: "photo"), primaryAction: UIAction { _ in }).creatingFixedGroup()
-
4:55 - Convenient form
// Creating the 'Draw' group // Convenient form of // UIBarButtonItemGroup.movableGroup(customizationIdentifier:representativeItem:items:) let drawGroup = UIBarButtonItem(title: "Draw", …) .creatingMovableGroup(customizationIdentifier: "Draw")
-
5:30 - Creating an optional group with multiple UIBarButtonItems using UIBarButtonItemGroup
let shapeGroup = UIBarButtonItemGroup.optionalGroup( customizationIdentifier: "Shapes", representativeItem: UIBarButtonItem(title: "Shapes", image: UIImage(systemName: "square.on.circle")), items: [ UIBarButtonItem(title: "Square", image: UIImage(systemName: "square"), primaryAction: UIAction { _ in }), UIBarButtonItem(title: "Circle", image: UIImage(systemName: "circle"), primaryAction: UIAction { _ in }), UIBarButtonItem(title: "Rectangle", image: UIImage(systemName: "rectangle"), primaryAction: UIAction { _ in }), UIBarButtonItem(title: "Diamond", image: UIImage(systemName: "diamond"), primaryAction: UIAction { _ in }), ])
-
6:56 - Setting up customizable centerItemGroups on a UINavigationItem
navigationItem.customizationIdentifier = "com.jetpack.blueprints.maineditor" navigationItem.centerItemGroups = [ // groups in the default customization UIBarButtonItem(title: "Insert", image: UIImage(systemName: "photo"), primaryAction: UIAction { _ in }).creatingFixedGroup(), UIBarButtonItem(title: "Draw", image: UIImage(systemName: "scribble"), primaryAction: UIAction { _ in }).creatingMovableGroup(customizationIdentifier: "Draw"), .optionalGroup(customizationIdentifier: "Shapes", representativeItem: UIBarButtonItem(title: "Shapes", image: UIImage(systemName: "square.on.circle")), items: [ UIBarButtonItem(title: "Square", image: UIImage(systemName: "square"), primaryAction: UIAction { _ in }), UIBarButtonItem(title: "Circle", image: UIImage(systemName: "circle"), primaryAction: UIAction { _ in }), UIBarButtonItem(title: "Rectangle", image: UIImage(systemName: "rectangle"), primaryAction: UIAction { _ in }), UIBarButtonItem(title: "Diamond", image: UIImage(systemName: "diamond"), primaryAction: UIAction { _ in }), ]), .optionalGroup(customizationIdentifier: "Text", items: [ UIBarButtonItem(title: "Label", image: UIImage(systemName: "character.textbox"), primaryAction: UIAction { _ in }), UIBarButtonItem(title: "Text", image: UIImage(systemName: "text.bubble"), primaryAction: UIAction { _ in }), ]), // additional group not in the default customization .optionalGroup(customizationIdentifier: "Format", isInDefaultCustomization: false, representativeItem: UIBarButtonItem(title: "BIU", image: UIImage(systemName: "bold.italic.underline")), items:[ UIBarButtonItem(title: "Bold", image: UIImage(systemName: "bold"), primaryAction: UIAction { _ in }), UIBarButtonItem(title: "Italic", image: UIImage(systemName: "italic"), primaryAction: UIAction { _ in }), UIBarButtonItem(title: "Underline", image: UIImage(systemName: "underline"), primaryAction: UIAction { _ in }), ]) ]
-
9:30 - Adding a "Comments" item to the default title menu
navigationItem.titleMenuProvider = { suggestedActions in var children = suggestedActions children += [ UIAction(title: "Comments", image: UIImage(systemName: "text.bubble")) { _ in } ] return UIMenu(children: children) }
-
10:15 - Supporting Drag & Drop and Sharing from the title menu
let url = <#T##URL#> let documentProperties = UIDocumentProperties(url: url) if let itemProvider = NSItemProvider(contentsOf: url) { documentProperties.dragItemsProvider = { _ in [UIDragItem(itemProvider: itemProvider)] } documentProperties.activityViewControllerProvider = { UIActivityViewController(activityItems: [itemProvider], applicationActivities: nil) } } navigationItem.documentProperties = documentProperties
-
12:45 - Implementing inline rename
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() navigationItem.renameDelegate = self } } extension ViewController: UINavigationItemRenameDelegate { func navigationItem(_ navigationItem: UINavigationItem, didEndRenamingWith title: String) { // Try renaming our document, the completion handler will have the updated URL or return an error. documentBrowserViewController.renameDocument(at: <#T##URL#>, proposedName: title, completionHandler: <#T##(URL?, Error?) -> Void#>) } }
-
14:05 - Implementing Search Suggestions
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() searchController.searchResultsUpdater = self } } extension ViewController: UISearchResultsUpdating { func fetchQuerySuggestions(for searchController: UISearchController) -> [(String, UIImage?)] { let queryText = searchController.searchBar.text // Here you would decide how to transform the queryText into search results. This example just returns something fixed. return [("Sample Suggestion", UIImage(systemName: "rectangle.and.text.magnifyingglass"))] } func updateSearch(_ searchController: UISearchController, query: String) { // This method is used to update the search UI from our query text change // You should also update internal state related to when the query changes, as you might for when the user changes the query by typing. searchController.searchBar.text = query } func updateSearchResults(for searchController: UISearchController) { let querySuggestions = self.fetchQuerySuggestions(for: searchController) searchController.searchSuggestions = querySuggestions.map { name, icon in UISearchSuggestionItem(localizedSuggestion: name, localizedDescription: nil, iconImage: icon) } } func updateSearchResults(for searchController: UISearchController, selecting searchSuggestion: UISearchSuggestion) { if let suggestion = searchSuggestion.localizedSuggestion { updateSearch(searchController, query: suggestion) } } }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。