ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
より進化したドキュメント起動体験の実現
ドキュメントベースのアプリを差別化し、最新のドキュメント起動体験でアプリ独自の個性を際立たせる方法を習得しましょう。新しいAPIを活用して、アプリ起動時にユーザーが最初に目にする画面をカスタマイズする方法をご紹介します。システムで用意されているデザインの新しいオプションを利用し、それらのデザインをカスタムアクションで修正できるほか、楽しい装飾的なビューやインパクトのあるアニメーションも利用できます。
関連する章
- 0:00 - Introduction
- 1:01 - Design overview
- 2:18 - Getting started with SwiftUI
- 3:13 - Getting started with UIKit
- 4:11 - Customization
- 6:42 - Adding template support to your app
リソース
- Building a document-based app with SwiftUI
- Customizing a document-based app’s launch experience
- Forum: UI Frameworks
関連ビデオ
WWDC23
WWDC20
-
ダウンロード
こんにちは SwiftUIチームのエンジニアのJuliaです このセッションでは ドキュメントベースのアプリケーションと それらを際立たせる 新しい方法についてお話しします 新しいカスタマイズ可能な 起動体験を組み込んで ドキュメントベースのアプリと その独自性をアピールしましょう 新しいデザインは 最初のドキュメントを作成する際に ユーザーをスムーズにガイドし 優れたカスタマイズオプションを提供するとともに テンプレートからのドキュメント作成にも 一流のサポートが提供されます 今日は 新しいドキュメント起動体験の 主な機能のいくつかを紹介します そして 新しいデザインを既存のアプリに 統合する方法を説明します
最後に アプリの独自性を示すことができる 新しいAPIを紹介します
それでは デザインの概要から始めましょう 新しい起動体験を採用した アプリの素晴らしい例として iPadOS用の Playgroundsが挙げられます その機能を紹介し Playgroundsがこのデザインを どのように利用しているかを見ていきます こちらは Swift Playgroundsの キャラクター Byteです Swiftを学ぶデベロッパをガイドし 励ましてくれます
Byteや タイトルビューの 前後にある装飾ビューは フォアグラウンドアクセサリと バックグラウンドアクセサリです これらによって アプリ固有の要素を 起動体験に 取り入れることができます アプリ名は前面中央に表示されます
Playgroundsでプライマリ ボタンをタップすると コーディングチュートリアルの 選択画面が開きます セカンダリボタンをタップすると 新しいアプリが作成され エディタが開きます ブラウザはアプリがサポートする ファイル形式の ドキュメントを表示するように 構成されています 背景は無地の色 グラデーション 画像 またはカスタムビューに 置き換えることができます 私はこの新しい体験が大好きで 自分のアプリでも 採用したいと思っています その素晴らしい候補が 私の姪 Yaelのために作った ストーリーテリングアプリです 彼女は物語を作るのが大好きなので 彼女の作文の体験を さらに良いものにしてあげたいと思います ここではドキュメントグループシーンを使って ドキュメント提供クロージャと 開いたドキュメントを表示する ビューを指定しました iOS 17 SDKでコンパイルすると 作文アプリは起動時に システムドキュメントブラウザを表示します ここで iOS 18 SDKで 再コンパイルすると アプリが新しいデザインで起動します タイトルビューの中央にある ボタンは 自動的に表示されます アプリがドキュメント作成を サポートしているからです 同じ機能はUIKitのドキュメントベースの アプリケーションでも利用できます これは ウィンドウの ルートビューコントローラとして UIDocumentViewControllerを 設定したアプリに対応しています もしアプリが ドキュメント表示に UIDocumentViewControllerを使っている場合 それはおそらくウィンドウの ビューコントローラ階層のルートである UIDocumentBrowserViewController から示されています ここでは ブラウザビューコントローラの デリゲートを指定して 選択されたドキュメントが表示されるように する必要がありました 新しい起動体験には 独自のブラウザが含まれているので アプリで新しいデザインを 有効にするには ルートをUIDocumentViewControllerに 置き換えるだけで済みます UIDocumentViewControllerの より詳しい概要については WWDC23の「Build better document-based apps」という セッションをご覧ください ここでまとめましょう ここまで アプリに新しいデザインを 組み込む方法について説明してきました 素晴らしいスタートです 次に アプリの起動体験を さらに高める新しいAPIを紹介します 私の姪の好きな色はピンクなので ピンクのエイリアンのジャングルの画像が 作文アプリ起動時の 素晴らしい背景になると思います
背景を指定するには SwiftUIアプリの定義で iOS 18に新しく追加された DocumentGroupLaunchSceneを宣言します 次に ボタンのタイトルを NewDocumentButtonを使用して 好きなタイトルに変更できます
ここで 起動体験に アプリ固有の要素を取り入れたいと思います 私の姪が大好きなもうひとつがロボットです 彼女がロボットについての物語を書くよう インスパイアできるかもしれないので デザインに追加しようと思います ロボットの画像を タイトルビューの先端に配置し 末尾には エイリアンフラワーを 配置したいと思います アクセサリを提供するには accessory view builderパラメータを使用します アクセサリビューをキャンバスと考えて すべての画像やビューを配置し それらの位置を シーンの境界やタイトルビューの フレームに対して調整します アクセサリビューのビルダーが提供する geometryパラメータには シーンやタイトルビューの フレームが含まれています position()やoffset()のようなモディファイアを使用してアクセサリをレイアウトします
私は2つのアクセサリビューを 追加したいと思います 一つはタイトルビューの先端に沿って表示し もう一つはエイリアンフラワーを 末尾に配置します アプリがUIDocumentViewControllerを 使ってドキュメントを表示している場合は 新しいlaunchOptionsプロパティを 使用してカスタマイズします viewDidLoadは ドキュメントビューコントローラの起動 オプションを構成するのに最適です これで デザインに装飾ビューを 追加する方法がわかりました ロボットとエイリアンフラワーの 画像が完成し ビューを生き生きとした ユニークなものにしています Yaelもきっと喜ぶでしょう
多くのアプリには アプリ定義のテンプレート からドキュメントを作成する機能があります テンプレートは 一貫した形式 レイアウト スタイルに従う必要があるドキュメントの 優れた出発点となります iPadOSのPlaygroundsアプリは 豊富なテンプレートセットを提供し デベロッパがビューをアニメートする方法や ジェスチャーを認識したり 音を再生したりする方法をガイドします テンプレートはディスクに保存することも Playgroundsのようにウェブから ダウンロードすることもできます 姪は物語の出発点として いくつかのテンプレートから 自由に選べることを とても気に入ると思います では早速 テンプレートから 新しいドキュメントを作成する オプションを追加してみましょう そのためには もう一つ アクションボタンを追加する必要があります ボタンのタイトルは とします ボタンがタップされると SwiftUIは非同期クロージャを呼び出し テンプレートから 作成されたドキュメントを返すよう求めます テンプレートピッカービューを示した後に ドキュメントを返したい場合は クロージャ内で継続を作成し それを保存します シートまたはフルスクリーンカバーを表示し カスタムビューでテンプレートを選択します 継続をTemplatePickerに渡したら そこから再開できます ユーザーがテンプレートを選択した後 アプリはこのテンプレートを使って ドキュメントを作成し 継続を呼び出して SwiftUIに返します SwiftUIは指定されたテンプレートを コピーして新しいドキュメントを作成します UIKitアプリの場合は まず UIDocument.CreationIntentを定義して ドキュメントテンプレートを表現します
次に UIDocumentViewController サブクラスで 起動オプションのプライマリ またはセカンダリアクションを このインテントによるドキュメント作成 アクションとして割り当てます 新しいドキュメントの リクエストを処理するには 起動オプションのブラウザビュー コントローラのデリゲートを割り当てます 最後に ブラウザのアクティブな ドキュメント作成インテントを読み取り どのドキュメントを作成するかを定めます
このようになります 数行のコードを追加するだけで アプリは事前定義された構造と プロットタイプでの 物語の作成をサポートします テンプレートピッカーは アプリに最適なカスタムデザインで 構築してください 新しい起動体験は素晴らしいので 皆さんのアプリに組み込まれるのを 見るのが楽しみです まずはiOS 18 SDKでSwiftUIアプリを 再コンパイルするところから 始めてみてください 次に DocumentGroupLaunchSceneを 追加して起動体験をカスタマイズし アプリの独自性をアピールしましょう UIKitアプリの場合は UIDocumentViewControllerを ルートビューコントローラにして 起動オプションに カスタマイズを適用します すべてのアプリケーションには それぞれ特別な魅力があります 新しいAPIを導入して アプリの独自性を強調し 一目でわかるようにしていきましょう ここまで ご視聴いただきありがとうございました ドキュメント起動体験を通じて アプリのストーリーを伝えていきましょう
-
-
2:38 - Document-based application
@main struct WritingApp: App { var body: some Scene { DocumentGroup(newDocument: { StoryDocument() }) { file in StoryView(document: $file.document) } } }
-
3:26 - Presenting a document from the browser in iOS 17
class DocumentViewController: UIDocumentViewController { ... } let documentViewController = DocumentViewController() let browserViewController = UIDocumentBrowserViewController( forOpening: [.plainText] ) window.rootViewController = browserViewController
-
3:38 - Presenting a document from the browser in iOS 17
class DocumentViewController: UIDocumentViewController { ... } let documentViewController = DocumentViewController() let browserViewController = UIDocumentBrowserViewController( forOpening: [.plainText] ) window.rootViewController = browserViewController browserViewController.delegate = self
-
3:43 - Presenting a document from the browser in iOS 17
class DocumentViewController: UIDocumentViewController { ... } let documentViewController = DocumentViewController() let browserViewController = UIDocumentBrowserViewController( forOpening: [.plainText] ) window.rootViewController = browserViewController browserViewController.delegate = self // MARK: UIDocumentBrowserViewControllerDelegate func documentBrowser( _ browser: UIDocumentBrowserViewController, didPickDocumentsAt documentURLs: [URL] ) { guard let url = documentURLs.first else { return } documentViewController.document = StoryDocument(fileURL: url) browser.present(documentViewController, animated: true) }
-
3:56 - Presenting a document from the browser in iOS 18
class DocumentViewController: UIDocumentViewController { ... } let documentViewController = DocumentViewController() window.rootViewController = documentViewController
-
4:38 - Customize the document launch experience: background
DocumentGroup( newDocument: { StoryDocument() } ) { file in StoryView(document: $file.document) } DocumentGroupLaunchScene { ... } background: { Image(.pinkJungle) .resizable() .aspectRatio(contentMode: .fill) }
-
4:49 - Customize the document launch experience: new document button title
DocumentGroup( newDocument: { StoryDocument() } ) { file in StoryView(document: $file.document) } DocumentGroupLaunchScene { NewDocumentButton("Start Writing") } background: { Image(.pinkJungle) .resizable() .aspectRatio(contentMode: .fill) }
-
5:29 - Customize the document launch experience: accessory views
DocumentGroupLaunchScene { NewDocumentButton("Start Writing") } background: { Image(.pinkJungle) .resizable() .aspectRatio(contentMode: .fill) } overlayAccessoryView: { }
-
5:44 - Position accessory views
DocumentGroupLaunchScene { NewDocumentButton("Start Writing") } background: { Image(.pinkJungle) .resizable() .aspectRatio(contentMode: .fill) } overlayAccessoryView: { geometry in }
-
5:53 - Position accessory views
DocumentGroupLaunchScene { NewDocumentButton("Start Writing") } background: { ... } overlayAccessoryView: { geometry in ZStack { Image(.robot) .position( x: geometry.titleViewFrame.minX, y: geometry.titleViewFrame.minY ) Image(.plant) .position( x: geometry.titleViewFrame.maxX, y: geometry.titleViewFrame.maxY ) } }
-
6:11 - Customize the document launch experience in a UIKit app
class DocumentViewController: UIDocumentViewController { override func viewDidLoad() { super.viewDidLoad() // Update the background launchOptions.background.image = UIImage(resource: .pinkJungle) // Add foreground accessories launchOptions.foregroundAccessoryView = ForegroundAccessoryView() } }
-
7:31 - Create a document from a template: add a button
DocumentGroupLaunchScene { NewDocumentButton("Start Writing") NewDocumentButton("Choose a Template", for: StoryDocument.self) { } }
-
7:45 - Create a document from a template: return document later
@State private var creationContinuation: CheckedContinuation<StoryDocument?, any Error>? DocumentGroupLaunchScene { NewDocumentButton("Start Writing") NewDocumentButton("Choose a Template", for: StoryDocument.self) { try await withCheckedThrowingContinuation { continuation in self.creationContinuation = continuation } } }
-
7:56 - Create a document from a template: present a template picker
@State private var creationContinuation: CheckedContinuation<StoryDocument?, any Error>? @State private var isTemplatePickerPresented = false DocumentGroupLaunchScene { NewDocumentButton("Start Writing") NewDocumentButton("Choose a Template", for: StoryDocument.self) { try await withCheckedThrowingContinuation { continuation in self.creationContinuation = continuation self.isTemplatePickerPresented = true } } .sheet(isPresented: $isTemplatePickerPresented) { TemplatePicker(continuation: $creationContinuation } }
-
8:07 - Create a document from a template: template picker view
struct TemplatePicker: View { @Binding var creationContinuation: CheckedContinuation<StoryDocument?, any Error>? var body: some View { Button("Three Act Structure") { creationContinuation?.resume(returning: StoryDocument.threeActStructure()) creationContinuation = nil } } } extension StoryDocument { static func threeActStructure() -> Self { Self.init(...) } }
-
8:20 - Create a document from a template in UIKit
extension UIDocument.CreationIntent { static let template = UIDocument.CreationIntent("template") }
-
8:29 - Create a document from a template in UIKit
launchOptions.secondaryAction = LaunchOptions.createDocumentAction(with: .template) launchOptions.browserViewController.delegate = self // MARK: UIDocumentBrowserViewControllerDelegate func documentBrowser( _ browser: UIDocumentBrowserViewController, didRequestDocumentCreationWithHandler importHandler: @escaping (URL?, ImportMode) -> Void) { switch browser.activeDocumentCreationIntent { case .template: presentTemplatePicker(with: importHandler) default: let newDocumentURL = // ... importHandler(newDocumentURL, .copy) } }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。