스트리밍은 대부분의 브라우저와
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
-
다운로드
안녕하세요 제 이름은 Julia이고 SwiftUI 팀의 엔지니어입니다 이 동영상에서는 문서 기반 응용 프로그램과 이 앱을 돋보이게 하는 새로운 방법을 설명하겠습니다 새로운 맞춤형 실행 경험을 도입하여 문서 기반 앱과 앱의 고유한 아이덴티티를 선보일 수 있습니다 새로운 디자인은 사용자가 쉽게 첫 문서를 만들 수 있게 안내하고 멋진 맞춤화 옵션과 템플릿에서의 문서 생성에 대한 최고 수준의 지원을 제공합니다 오늘은 새로운 문서 실행 경험의 주요 기능 몇 가지를 설명하겠습니다 새로운 디자인을 기존 응용 프로그램에 통합하는 방법을 알아보겠습니다
그리고 마지막으로, 앱의 독창성을 선보이도록 지원하는 새로운 API 몇 가지를 소개하겠습니다
디자인의 개요부터 시작해 보죠 새로운 실행 경험을 도입한 앱을 잘 보여 주는 예는 iPadOS용 Playgrounds입니다 기능에 대해 설명해 드리고 Playgrounds가 어떻게 이 디자인에 기능을 활용했는지 보여 드릴게요 Byte는 Swift Playgrounds의 캐릭터입니다 개발자가 Swift를 학습하는 과정을 안내하고 독려하죠
제목 보기의 앞, 뒤에 있는 다른 장식적인 보기와 Byte는 전면 및 배경 액세서리입니다 이러한 액세서리를 사용하면 앱에 고유한 요소를 실행 경험에 가져올 수 있죠 앱이 이름은 전면 중앙에 표시됩니다
기본 버튼을 탭하면 Playgrounds에서 선별된 코딩 튜토리얼을 엽니다 보조 버튼을 탭하면 Playgrounds에서 새 앱을 생성하고 편집기를 엽니다 브라우저는 앱에서 지원되는 파일 형식의 문서를 표시하도록 구성되어 있습니다 배경은 단색이나 그라디언트, 이미지 또는 선택한 맞춤형 보기로 바꿀 수 있습니다 저는 이 새 경험이 마음에 들고 제 앱 중 하나에 도입하고 싶습니다 그리고 딱 맞는 후보도 있죠 제가 조카인 Yael을 위해 만든 스토리텔링 앱이 있습니다 Yael은 이야기를 만드는 걸 좋아하기 때문에 저는 Yael의 글쓰기 경험을 한층 더 향상해 주고 싶었죠 저는 문서 그룹 장면을 사용하여 문서 제공 클로저와 열린 문서를 표시하는 보기를 지정했습니다 iOS 17 SDK로 컴파일하면 글쓰기 앱을 실행했을 때 시스템 문서 브라우저가 표시되죠 이제 iOS 18 SDK로 다시 컴파일하면 앱이 완전히 새로운 디자인으로 실행됩니다 제목 보기의 중앙에 ‘문서 생성’ 버튼이 자동으로 표시됩니다 앱에서 문서 생성을 지원하기 때문이죠 동일한 기능을 UIKit 문서 기반 앱에 사용할 수 있습니다 윈도우의 루트 보기 컨트롤러로 설정된 UIDocumentViewController를 사용하는 앱에서 지원되죠 앱에서 UIDocumentViewController를 사용하여 문서를 표시하는 경우 윈도우의 보기 컨트롤러 계층의 루트인 UIDocumentBrowserViewController에서 표시될 가능성이 높습니다 선택 시 문서를 제시하려면 브라우저 보기 컨트롤러의 대리자를 지정해야 했습니다 새 실행 경험에는 이미 자체 브라우저가 포함되어 있으므로 앱에서 새 디자인을 활성화하려면 루트를 UIDocumentViewController로 대체하기만 하면 됩니다 UIDocumentViewController의 자세한 개요를 알아보려면 WWDC23의 더 나은 문서 기반 앱 빌드하기 비디오를 시청하세요 잠시 멈추고 요약해 보겠습니다 지금까지 새로운 디자인을 앱에 통합하는 방법을 알아봤어요 좋은 시작이죠 이제 앱의 실행 경험을 더 향상할 수 있게 지원하는 새로운 API를 소개하겠습니다 조카는 분홍색을 좋아합니다 분홍색의 이국적인 정글 이미지를 글쓰기 앱 실행 경험의 배경으로 사용하면 좋겠네요
배경을 지정하려면 SwiftUI 앱 정의에서 iOS 18의 새로운 기능인 DocumentGroupLaunchScene을 선언합니다 그런 다음 ‘문서 생성’ 버튼의 제목을 변경할 수 있습니다 원하는 제목의 NewDocumentButton을 작성해서요
이제, 제 앱에만 해당되는 몇 가지 요소를 실행 경험으로 가져오고 싶은데요 제 조카가 좋아하고 흥미를 갖는 또 다른 하나는 로봇입니다 조카에게 로봇에 대한 이야기를 쓰도록 영감을 줄 수도 있겠죠? 디자인에 하나 추가할게요 로봇 이미지를 제목 보기의 앞 가장자리를 따라 배치하고 이국적인 꽃을 뒤쪽 가장자리에 배치하려 합니다 액세서리를 제공하려면 액세서리 보기 빌더 매개변수를 사용해야죠 액세서리 보기를 모든 이미지와 보기를 넣을 캔버스로 생각하고 이를 배치하세요 장면 경계선과 제목 보기의 프레임에 비례해서 말이죠 액세서리 보기 빌더는 지오메트리 매개변수를 제공하는데 여기에는 장면과 제목 보기의 프레임이 포함되어 있습니다 position() 또는 offset() 같은 한정자를 사용해 액세서리를 배치하죠
저는 두 개의 액세서리 보기를 추가하려고 합니다 하나는 제목 보기의 앞 가장자리를 따라 배치하고 또 다른 하나, 이국적인 꽃은 뒤쪽 가장자리에 배치할 거예요 앱에서 UIDocumentViewController를 사용하여 문서를 표시하는 경우 새로운 launchOptions 속성을 사용하여 사용자화하세요 viewDidLoad는 문서 보기 컨트롤러의 실행 옵션을 구성하기에 적합한 곳입니다 지금까지 디자인에 장식적 보기를 추가하는 방법을 알아봤습니다 로봇과 이국적인 꽃의 이미지가 완성되어서 보기에 생동감을 더하고 독창적인 디자인을 만들었죠 Yael이 보면 정말 좋아하겠네요
많은 앱에서 앱 정의 템플릿으로 문서를 생성하는 기능을 제공하죠 템플릿은 일관된 형식, 레이아웃 또는 스타일을 준수해야 하는 문서의 훌륭한 시작점 역할을 합니다 iPadOS의 Playgrounds 앱은 풍부한 템플릿을 제공합니다 이러한 템플릿은 개발자에게 보기에 애니메이션을 적용하고 제스처를 인식하고, 사운드를 재생하는 방법을 안내합니다 템플릿은 디스크에 저장하거나 웹에서 다운로드할 수 있습니다 Playgrounds에서처럼요 제 조카는 여러 템플릿 중에 선택해서 이야기를 시작하기 위한 소재를 활용하고 싶어 할 거예요 템플릿에서 새 문서를 생성하는 옵션을 지금 추가해 보죠 이렇게 하려면 동작 버튼을 하나 더 탭해야 합니다 버튼의 제목은 ‘템플릿 선택’으로 하겠습니다 버튼을 탭하면 SwiftUI가 async 클로저를 호출하여 템플릿에서 생성된 문서를 반환하도록 요청합니다 템플릿 선택기 보기를 제시한 후 나중에 문서를 반환하고 싶은 경우 클로저에서 연속성을 생성하고 저장합니다 시트 또는 전체 화면 커버를 맞춤형 보기로 제시하여 템플릿을 선택합니다 연속성을 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) } }
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.