版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2021.03.21 星期日 |
前言
今天翻閱蘋果的API文檔,發(fā)現(xiàn)多了一個框架SwiftUI,這里我們就一起來看一下這個框架。感興趣的看下面幾篇文章。
1. SwiftUI框架詳細(xì)解析 (一) —— 基本概覽(一)
2. SwiftUI框架詳細(xì)解析 (二) —— 基于SwiftUI的閃屏頁的創(chuàng)建(一)
3. SwiftUI框架詳細(xì)解析 (三) —— 基于SwiftUI的閃屏頁的創(chuàng)建(二)
4. SwiftUI框架詳細(xì)解析 (四) —— 使用SwiftUI進(jìn)行蘋果登錄(一)
5. SwiftUI框架詳細(xì)解析 (五) —— 使用SwiftUI進(jìn)行蘋果登錄(二)
6. SwiftUI框架詳細(xì)解析 (六) —— 基于SwiftUI的導(dǎo)航的實現(xiàn)(一)
7. SwiftUI框架詳細(xì)解析 (七) —— 基于SwiftUI的導(dǎo)航的實現(xiàn)(二)
8. SwiftUI框架詳細(xì)解析 (八) —— 基于SwiftUI的動畫的實現(xiàn)(一)
9. SwiftUI框架詳細(xì)解析 (九) —— 基于SwiftUI的動畫的實現(xiàn)(二)
10. SwiftUI框架詳細(xì)解析 (十) —— 基于SwiftUI構(gòu)建各種自定義圖表(一)
11. SwiftUI框架詳細(xì)解析 (十一) —— 基于SwiftUI構(gòu)建各種自定義圖表(二)
12. SwiftUI框架詳細(xì)解析 (十二) —— 基于SwiftUI創(chuàng)建Mind-Map UI(一)
13. SwiftUI框架詳細(xì)解析 (十三) —— 基于SwiftUI創(chuàng)建Mind-Map UI(二)
14. SwiftUI框架詳細(xì)解析 (十四) —— 基于Firebase Cloud Firestore的SwiftUI iOS程序的持久性添加(一)
15. SwiftUI框架詳細(xì)解析 (十五) —— 基于Firebase Cloud Firestore的SwiftUI iOS程序的持久性添加(二)
16. SwiftUI框架詳細(xì)解析 (十六) —— 基于SwiftUI簡單App的Dependency Injection應(yīng)用(一)
17. SwiftUI框架詳細(xì)解析 (十七) —— 基于SwiftUI簡單App的Dependency Injection應(yīng)用(二)
18. SwiftUI框架詳細(xì)解析 (十八) —— Firebase Remote Config教程(一)
19. SwiftUI框架詳細(xì)解析 (十九) —— Firebase Remote Config教程(二)
20. SwiftUI框架詳細(xì)解析 (二十) —— 基于SwiftUI的Document-Based App的創(chuàng)建(一)
21. SwiftUI框架詳細(xì)解析 (二十一) —— 基于SwiftUI的Document-Based App的創(chuàng)建(二)
22. SwiftUI框架詳細(xì)解析 (二十二) —— 基于SwiftUI的AWS AppSync框架的使用(一)
23. SwiftUI框架詳細(xì)解析 (二十三) —— 基于SwiftUI的AWS AppSync框架的使用(二)
24. SwiftUI框架詳細(xì)解析 (二十四) —— 基于SwiftUI的編輯占位符的使用(一)
25. SwiftUI框架詳細(xì)解析 (二十五) —— 基于SwiftUI的編輯占位符的使用(二)
開始
首先看下主要內(nèi)容:
了解如何使用Xcode 12的多平臺應(yīng)用程序模板和
SwiftUI
編寫可在每個Apple
平臺上運行的單個應(yīng)用程序。內(nèi)容來自翻譯。
下面看下寫作環(huán)境:
Swift 5, iOS 14, Xcode 12
接著就是正文啦。
自Mac Catalyst
發(fā)布以來,蘋果一直在為讓iOS開發(fā)人員將其應(yīng)用程序帶到Mac鋪平道路。擴(kuò)展到SwiftUI
(Apple建立用戶界面的一種簡單的聲明式方法),現(xiàn)在您可以使用它來構(gòu)建整個應(yīng)用程序。這些擴(kuò)展以及Xcode 12
中新增的多平臺應(yīng)用程序模板(multiplatform app template),使您可以使用一個代碼庫為每個Apple平臺構(gòu)建應(yīng)用程序。
在本教程中,您將了解:
-
Xcode 12
的多平臺應(yīng)用程序模板(multiplatform app template) -
App
協(xié)議 -
App
,Scenes
和Views
如何組合在一起 - 相同代碼適應(yīng)每個平臺的方式
- 如何在重用視圖時為每個平臺創(chuàng)建自定義UI
您將通過為RayGem
添加新功能(適用于iOS
,iPadOS
和macOS
的應(yīng)用程序來顯示有關(guān)不同寶石的信息)來學(xué)習(xí)所有這些內(nèi)容。
注意:本教程假定您熟悉
SwiftUI
。如果您只是入門,請查看SwiftUI: Getting Started。RayGem
還利用Core Data
。盡管您不需要深入了解Core Data
,但如果您想了解更多信息,這是一個很好的起點: Core Data with SwiftUI Tutorial: Getting Started。
打開項目材料。 在啟動文件夾中打開RayGem.xcodeproj
。 構(gòu)建并運行。
RayGem
是一個簡單的多平臺應(yīng)用程序,其中列出了寶石(寶石或半寶石)的集合。 用戶可以閱讀有關(guān)他們的有趣事實,并保存他們的收藏夾。
您已經(jīng)可以滾動并點擊寶石以閱讀有關(guān)每個寶石的事實。 該應(yīng)用程序具有從Core Data
獲取和保存喜歡的寶石的代碼,但是它既不能保存也不能列出喜歡的寶石。 您將在本教程中添加此功能。
在啟動程序項目中打開不同的視圖,以熟悉該應(yīng)用程序。 該應(yīng)用程序的主視圖位于GemList.swift
中,顯示了從Core Data
存儲中獲取的GemRow.swift
中找到的行的列表。 通過點擊一行,您可以導(dǎo)航到DetailsView.swift
中的詳細(xì)信息視圖。
1. Considering the Project Structure
在開始進(jìn)行任何更改之前,請看一下啟動項目。 請注意,這些組與您通常的iOS入門項目中的組有何不同。
創(chuàng)建新項目時,Xcode 12
有一個名為Multiplatform
的新部分。 在其中,您會找到適用于多平臺應(yīng)用程序的新模板。 本教程的入門項目是使用此模板構(gòu)建的。
此模板創(chuàng)建三個組:
-
iOS:
iOS
專用代碼 -
macOS:
macOS
專用代碼 - Shared:兩個平臺的代碼,包括模型,業(yè)務(wù)邏輯和可重用視圖
SwiftUI
允許您在平臺之間共享UI代碼,并根據(jù)設(shè)備自動調(diào)整UI。 您可以創(chuàng)建可在每個平臺上重用的視圖,但是某些行為更適合某些平臺。 這樣,每個平臺都有一個組,可以讓您為每個平臺編寫特定的代碼,同時仍可以重用許多代碼。
Understanding the New App and Scene Protocol
在Shared
組中打開AppMain.swift
。
@main
struct AppMain: App {
let persistenceController = PersistenceController.shared
var body: some Scene {
WindowGroup {
ContentView()
.environment(
\.managedObjectContext,
persistenceController.container.viewContext)
}
}
}
在iOS 14
中,Apple引入了新的App
協(xié)議,該協(xié)議處理應(yīng)用程序的生命周期,并取代了舊的AppDelegate.swift
和SceneDelegate.swift
。
與View
協(xié)議非常相似,App
協(xié)議要求您通過返回Scene
來實現(xiàn)主體body
。主體將成為您應(yīng)用程序的根視圖。通常,您會返回一個WindowGroup
,這是一種特殊的Scene
類型,它是應(yīng)用程序視圖層次結(jié)構(gòu)的容器。 SwiftUI
和WindowGroup
共同負(fù)責(zé)在每個平臺上以不同的方式呈現(xiàn)您的應(yīng)用程序。例如,在macOS
上,WindowGroups
將在其菜單欄中自動具有窗口管理選項,并支持在選項卡中收集應(yīng)用程序的所有窗口。
Swift 5.3
引入了新的@main
屬性,以指示應(yīng)用程序的入口點。通過將此屬性添加到實現(xiàn)App
的結(jié)構(gòu)中,SwiftUI
將以該結(jié)構(gòu)為應(yīng)用程序的起點。
Running on macOS
該應(yīng)用程序已經(jīng)具有可在iOS上運行的基本功能,但是macOS
呢?將target
從RayGem(iOS)
更改為RayGem(macOS)
,然后生成并再次運行。
該應(yīng)用程序不包含任何iOS
或macOS
特定代碼,它們都是使用普通的舊版SwiftUI
構(gòu)建的,就像您構(gòu)建其他任何應(yīng)用程序一樣。 但是,您仍然可以在iOS
和macOS
上運行您的應(yīng)用程序! 那不是很酷嗎?
使用新的Multiplatform
應(yīng)用程序模板,Xcode
為您的應(yīng)用程序創(chuàng)建了兩個targets
:一個用于在iOS
和iPadOS
上運行,另一個用于在macOS
上運行。 它使用這些target
在每個相應(yīng)平臺上運行您的應(yīng)用程序。
1. Understanding how SwiftUI Adapts to the Platform
請注意,SwiftUI
如何針對每個平臺調(diào)整UI。 在iOS
上,它使用帶有列表的導(dǎo)航視圖。 當(dāng)用戶點擊一行時,它將推送該行的目標(biāo)視圖。 在macOS
上,它使用帶有側(cè)邊列表和內(nèi)容視圖的窗口。 當(dāng)用戶單擊一行時,內(nèi)容視圖將更新為該行的目標(biāo)視圖。
現(xiàn)在,將target
切換回RayGem(iOS)
,并在iPad
模擬器上構(gòu)建并運行。
當(dāng)應(yīng)用程序在iPadOS
上運行時,列表將隱藏在視圖的左側(cè),而當(dāng)用戶選擇gem
時,主視圖將顯示目標(biāo)視圖。
Polishing the macOS app
UI
已經(jīng)適應(yīng)了不同的設(shè)備大小,甚至可以在macOS
上調(diào)整窗口大小,但是有時候,您可能希望在某些設(shè)備上添加一些限制,同時在其他設(shè)備上保持相同的行為。 值得慶幸的是,SwiftUI
包含許多修飾符,以影響它如何將視圖適應(yīng)不同的平臺。 告訴SwiftUI
如何處理您的應(yīng)用,可以使您的應(yīng)用成為更好的macOS
成員。
1. Adding a minimum width to your list
現(xiàn)在,您可以在macOS
上調(diào)整gem
側(cè)面列表的大小,并將其縮小為零。
這是一種行為,可能會使某些用戶感到困惑。 SwiftUI
為您提供了修飾符來處理這種情況,而無需為每個平臺編寫特定的代碼。
打開GemList.swift
,找到// TODO: Add min frame here
。 并在注釋下方添加以下行:
.frame(minWidth: 250)
構(gòu)建并在iPhone
模擬器上運行以查看結(jié)果。
此修飾符將最小寬度添加到列表中。 在iOS
上,這可能沒有多大意義,因為列表將使用視圖的整個寬度。 但是,在macOS
上,此修飾符可確保列表List
保持最小寬度為250
點,同時仍允許用戶調(diào)整其大小。
將target
更改為RayGem(macOS)
,然后構(gòu)建并再次運行。 嘗試調(diào)整列表的大小。
請注意,邊列表仍可以調(diào)整大小,但始終保持超過250
點的寬度。
2. Adding a navigation title
仍在GemList.swift
中,請注意列表底部的修飾符navigationTitle(_ :)
。 這是iOS 14
上引入的新修飾符,用于配置視圖的標(biāo)題。 在iOS
和watchOS
上,它將使用字符串作為導(dǎo)航視圖的標(biāo)題。 iPadOS
將設(shè)置主導(dǎo)航視圖標(biāo)題和應(yīng)用程序切換器中標(biāo)題。 這對于區(qū)分您的應(yīng)用實例很重要。 在macOS
上,窗口標(biāo)題欄和Mission Control
使用此字符串作為標(biāo)題。
Working With Toolbars
現(xiàn)在,該讓用戶擁有保存自己喜歡的寶石的能力了。
在DetailsView.swift
中,將以下內(nèi)容添加到視圖的底部:
func toggleFavorite() {
gem.favorite.toggle()
try? viewContext.save()
}
此方法切換當(dāng)前gem
上的favorite
屬性并將更改保存到Core Data
。
接下來,找到// TODO: Add favorite button here
,并在注釋下方添加以下代碼:
// 1
.toolbar {
// 2
ToolbarItem {
Button(action: toggleFavorite) {
// 3
Label(
gem.favorite ? "Unfavorite" : "Favorite",
systemImage: gem.favorite ? "heart.fill" : "heart"
)
.foregroundColor(.pink)
}
}
}
這是代碼的細(xì)分:
- 1)
iOS 14
引入了新的視圖修飾符:toolbar(content:)
。 此修飾符采用表示toolbar
內(nèi)容的ToolbarItem
。 - 2) 使用一個按鈕添加一個
ToolbarItem
,以在gem
上切換favorite
。 - 3) 接下來,添加
Label
作為按鈕的內(nèi)容,標(biāo)題為“Favorite” or “Unfavorite”
,并顯示心形圖像。
構(gòu)建并運行。 然后,收藏一顆寶石。
現(xiàn)在,在macOS
上構(gòu)建并運行。 喜歡一個寶石可以看到結(jié)果。
SwiftUI
使用ToolbarItem
并將其放置在每個平臺的預(yù)期位置。 在iOS
上,它遵循bar
的顏色方案,將Label
的圖像用作導(dǎo)航欄上的按鈕。 在macOS
上,它也使用Label
的圖像。 但是,如果您調(diào)整窗口的大小并且在工具欄上的按鈕上沒有任何空間,它將創(chuàng)建帶有Label
標(biāo)題的菜單按鈕。
將窗口調(diào)整為可能的最小寬度。
SwiftUI
會針對每個平臺調(diào)整UI,即使在調(diào)整窗口大小時也找到了顯示按鈕的最佳方法。
Understanding tab views on different platforms
現(xiàn)在用戶可以收藏自己的寶石了,可以列出這些收藏夾了。
入門項目已經(jīng)附帶了此代碼,即FavoriteGems
視圖。 該視圖獲取并列出所有將favorite
屬性設(shè)置為true
的寶石。
打開ContentView.swift
并將以下枚舉添加到文件頂部:
enum NavigationItem {
case all
case favorites
}
該枚舉描述了應(yīng)用程序的兩個選項卡。 接下來,通過將body
的內(nèi)容替換為以下內(nèi)容來添加tab view
:
// 1
TabView {
// 2
NavigationView {
GemList()
}
.tabItem { Label("All", systemImage: "list.bullet") }
.tag(NavigationItem.all)
// 3
NavigationView {
FavoriteGems()
}
.tabItem { Label("Favorites", systemImage: "heart.fill") }
.tag(NavigationItem.favorites)
}
上面的代碼是這樣的:
- 1) 首先,創(chuàng)建一個
TabView
作為根視圖。 - 2) 接下來,添加
GemList
作為其第一個視圖,并帶有一個標(biāo)題為“All”
的Label
和列表項目符號的圖像。 - 3) 添加
FavoriteGems
作為第二個視圖,并帶有一個標(biāo)題為Favorites
和小心圖像的Label
。
在iOS
上構(gòu)建并運行。 收藏一些寶石,然后打開Favorites
選項卡以查看其中列出的寶石。
接下來,將target
更改為macOS
。 構(gòu)建并運行以查看SwiftUI
如何適配macOS
上的UI
。
極好的! 您已經(jīng)有一個可以在iOS
和macOS
上運行的簡單應(yīng)用程序! 花一點時間享受您到目前為止所取得的成就。
Optimizing the User Experience for Each Platform
SwiftUI
嘗試使代碼中聲明的UI
適應(yīng)每個平臺。 iOS
上的TabBar
在底部具有其欄,圖像和文本作為按鈕。 在macOS
上,它使用帶有標(biāo)題的視圖頂部的欄,非常類似于segmented view
。
即使SwiftUI
可以在每個平臺上調(diào)整用戶界面,但這并不意味著它總是能夠創(chuàng)建用戶期望的內(nèi)容。 與在macOS
上使用TabBar
相比,更好的布局是帶有類別列表的Sidebar
。 然后,一個列表將顯示所選類別的每個元素。
您的應(yīng)用程序已經(jīng)可以在兩個平臺上運行,但是用戶希望在任何地方都能獲得最佳體驗。 值得慶幸的是,Apple
添加了一種在多平臺應(yīng)用程序中創(chuàng)建特定于平臺的視圖的方法。 這正是Xcode
中的macOS
和iOS
組的用途! 您現(xiàn)在將更新應(yīng)用程序中的tab bar
,以將邊欄sidebar
布局用于macOS
。
1. Updating the macOS UI
在macOS
組內(nèi)創(chuàng)建一個新的SwiftUI View
文件,并將其命名為GemListViewer.swift
。 僅選擇macOS target membership
。
首先,向視圖添加新的屬性和方法:
@State var selection: NavigationItem? = .all
func toggleSideBar() {
NSApp.keyWindow?.firstResponder?.tryToPerform(
#selector(NSSplitViewController.toggleSidebar),
with: nil)
}
這是一個狀態(tài)變量,您將使用側(cè)邊欄中的當(dāng)前所選類別進(jìn)行更新:所有寶石或僅收藏的寶石。 當(dāng)用戶單擊按鈕時,toggleSideBar()
將顯示或隱藏側(cè)邊欄; 您會稍等一下。
接下來,將以下計算的屬性添加到視圖中:
var sideBar: some View {
List(selection: $selection) {
NavigationLink(
destination: GemList(),
tag: NavigationItem.all,
selection: $selection
) {
Label("All", systemImage: "list.bullet")
}
.tag(NavigationItem.all)
NavigationLink(
destination: FavoriteGems(),
tag: NavigationItem.favorites,
selection: $selection
) {
Label("Favorites", systemImage: "heart")
}
.tag(NavigationItem.favorites)
}
// 3
.frame(minWidth: 200)
.listStyle(SidebarListStyle())
.toolbar {
// 4
ToolbarItem {
Button(action: toggleSideBar) {
Label("Toggle Sidebar", systemImage: "sidebar.left")
}
}
}
}
您將創(chuàng)建一個側(cè)邊欄sidebar
視圖,其中包含一個包含兩個NavigationLinks
的List
—— 一個用于GemList
,一個用于FavoriteGems
。 通過使用SidebarListStyle
,您可以告訴SwiftUI
將此List
顯示為側(cè)邊欄sidebar
,以便用戶選擇要查看的類別。 您還可以在工具欄內(nèi)創(chuàng)建一個ToolbarItem
,并帶有一個按鈕來切換側(cè)欄sidebar
。 macOS
應(yīng)用中的預(yù)期行為是可以隱藏和顯示側(cè)邊欄。
接下來,將body
的內(nèi)容替換為以下內(nèi)容:
NavigationView {
sideBar
Text("Select a category")
.foregroundColor(.secondary)
Text("Select a gem")
.foregroundColor(.secondary)
}
這將顯示sidebar
以及一些文本。
最后,將previews
的內(nèi)容替換為以下內(nèi)容:
GemListViewer()
.environment(
\.managedObjectContext,
PersistenceController.preview.container.viewContext)
您已經(jīng)完成了macOS UI
的操作,但是暫時還看不到它。 首先,您將轉(zhuǎn)到iOS UI。
2. Updating the iOS UI
在iOS
組中創(chuàng)建另一個SwiftUI
視圖,并將其命名為GemListViewer.swift
。 這次,請確保僅選擇iOS target
。
將視圖的body
替換為以下內(nèi)容:
// 1
TabView {
// 2
NavigationView {
GemList()
.listStyle(InsetGroupedListStyle())
}
.tabItem { Label("All", systemImage: "list.bullet") }
.tag(NavigationItem.all)
// 3
NavigationView {
FavoriteGems()
.listStyle(InsetGroupedListStyle())
}
.tabItem { Label("Favorites", systemImage: "heart.fill") }
.tag(NavigationItem.favorites)
}
這是上面的代碼中發(fā)生的事情:
- 1) 將
TabView
聲明為根視圖,但這一次,僅適用于iOS
。 - 2) 將
GemList
添加為第一個視圖。 - 3) 接下來,添加
FavoriteGems
作為第二個視圖。
請注意,這正是您當(dāng)前在**ContentView.swift**
中擁有的代碼。
接下來,用以下代碼替換previews
的內(nèi)容:
Group {
GemListViewer()
GemListViewer()
.previewDevice(PreviewDevice(rawValue: "iPad Air 2"))
}
.environment(
\.managedObjectContext,
PersistenceController.preview.container.viewContext)
您設(shè)置了默認(rèn)情況下將使用iPhone
布局的預(yù)覽,然后添加了指定了iPad Air 2
布局的第二個預(yù)覽。
最后,再次打開ContentView.swift
,并用以下單行代碼替換body
的所有內(nèi)容:
GemListViewer()
構(gòu)建并運行iOS target
。
現(xiàn)在,構(gòu)建并運行macOS target
。
ContentView
是兩個平臺之間的共享視圖。但是,您的項目有兩個GemListViewer
,但一個僅包含在macOS target
中,另一個僅包含在iOS target
中。通過這種設(shè)置,您的應(yīng)用將為每個平臺使用正確的GemListViewer
。這提供了在每個平臺上重用應(yīng)用程序的核心視圖的可能性,但也允許在每個平臺上使用自定義行為和UI。每個平臺具有相同視圖的不同版本,可讓您訪問特定于平臺的API
和功能,例如iOS InsetGroupedListStyle
或macOS
側(cè)欄切換。
Understanding Independent Scenes and View States
SwiftUI
已經(jīng)捆綁了許多多平臺應(yīng)用程序功能。使用WindowGroup
,可以在iPadOS
上添加對應(yīng)用程序的多個實例的支持,而在macOS
上可以支持多個窗口。它甚至添加了用于在macOS
上打開新窗口的通用鍵盤快捷鍵Command-N
。
在macOS
上構(gòu)建并運行。選擇一個寶石,然后使用File ? New Window
打開一個新窗口。或者,使用鍵盤快捷鍵Command-N
。
請注意,使用一個窗口不會影響另一個窗口的狀態(tài)。 舊窗口保持其狀態(tài),顯示您選擇的寶石。 同時,新窗口的行為類似于應(yīng)用程序的新實例,獨立于原始實例。
每個場景都會處理應(yīng)用程序的狀態(tài)并更新其視圖,但不會直接影響另一個場景。
SwiftUI
給macOS
帶來的另一個共同功能是能夠?qū)⑺?code>windows合并到選項卡tabs
中。 轉(zhuǎn)到Window ? Merge All Windows
。
每個選項卡的行為都不同,具有各自的狀態(tài)。
Adding Extra Functionality for macOS
大多數(shù)macOS
應(yīng)用程序的常見功能是Preferences…
菜單命令。 用戶將希望能夠通過轉(zhuǎn)到RayGem ? Preferences
或使用Command-
快捷方式來更改設(shè)置。
您將在macOS
版本中添加一個簡單的設(shè)置視圖,以便用戶查看有關(guān)該應(yīng)用程序的有用信息,例如版本號和清除他們喜歡的寶石的按鈕。
1. Creating the Preferences View
在Views
組內(nèi)創(chuàng)建一個新的SwiftUI View
文件。 將其命名為SettingsView.swift
并選擇macOS target
。 首先向視圖添加幾個方法和一個屬性:
// 1
@State var showAlert = false
// 2
var appVersion: String {
Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? ""
}
// 3
func showClearAlert() {
showAlert.toggle()
}
// 4
func clearFavorites() {
let viewContext = PersistenceController.shared.container.viewContext
let gemEntity = Gem.entity()
let batchUpdateRequest = NSBatchUpdateRequest(entity: gemEntity)
batchUpdateRequest.propertiesToUpdate = ["favorite": false]
do {
try viewContext.execute(batchUpdateRequest)
} catch {
print("Handle Error: \(error.localizedDescription)")
}
}
這些方法和屬性的作用如下:
- 1) 首先,聲明一個
@State
屬性showAlert
,用于在用戶嘗試清除自己喜歡的寶石時顯示警報。 - 2) 接下來,聲明
appVersion
屬性,該屬性從應(yīng)用程序捆綁包中的CFBundleShortVersionString
檢索此屬性。 - 3) 創(chuàng)建一種方法,當(dāng)用戶單擊
Clear Favorites
時顯示alert
。 - 4) 最后,聲明從
Core Data
中清除喜歡的寶石的方法。
接下來,用以下代碼替換body
的內(nèi)容:
ScrollView {
VStack {
Text("Settings")
.font(.largeTitle)
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
Image("rw-logo")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 400, height: 400)
Text("RayGem")
.font(.largeTitle)
Text("Gem Version: \(appVersion)")
Section {
Button(action: showClearAlert) {
Label("Clear Favorites", systemImage: "trash")
}
}
}
.frame(width: 600, height: 600)
.alert(isPresented: $showAlert) {
Alert(
title: Text("Are you sure?")
.font(.title)
.foregroundColor(.red),
message: Text("This action cannot be undone."),
primaryButton: .cancel(),
secondaryButton: .destructive(
Text("Clear"),
action: clearFavorites))
}
}
您可以在此處創(chuàng)建帶有標(biāo)題,應(yīng)用程序圖標(biāo),應(yīng)用程序名稱和Clear Favorites
按鈕的視圖body
。 當(dāng)用戶嘗試清除自己喜歡的寶石時,您還會顯示一條alert
,以免意外刪除所有喜歡的寶石。
接下來,打開AppMain.swift
并找到注釋// TODO: Add Settings view here
。 將此代碼添加到注釋下方:
// 1
#if os(macOS)
// 2
Settings {
// 3
SettingsView()
}
#endif
這是這樣做的:
- 1) 使用
#if os
預(yù)處理程序指令測試當(dāng)前平臺是否為macOS
。 這樣可以確保此代碼僅針對該應(yīng)用程序的macOS
版本進(jìn)行編譯。 您可以在應(yīng)用程序中的任何位置添加這些檢查,以添加特定于平臺的代碼。 您可以檢查的其他值包括iOS
,tvOS
和watchOS
。 - 2) 創(chuàng)建
Settings
類型的第二個scene
。 - 3) 將
SettingsView
添加到該scene
。
構(gòu)建并運行。 使用鍵盤快捷鍵Command-
,打開Preferences
視圖。 向下滾動并按Clear Favorites
。
您的macOS
應(yīng)用程序現(xiàn)在具有一個單獨的平臺特定的首選項窗口!
2. Adding a Keyboard Shortcut
macOS
和iPadOS
上的另一個很酷的功能是執(zhí)行操作的鍵盤快捷鍵(keyboard shortcuts)
。 用戶可以使用鍵盤快捷鍵來代替打開Preferences
,向下滾動并單擊按鈕以清除其收藏夾。
在Model
組中創(chuàng)建一個新的Swift
文件,然后選擇兩個目標(biāo)targets
。 將其命名為GemCommands.swift
并將以下代碼添加到文件中:
import SwiftUI
import CoreData
// 1
struct GemCommands: Commands {
var body: some Commands {
// 2
CommandMenu("Gems") {
Button(action: clearFavorites) {
Label("Clear Favorites", systemImage: "trash")
}
// 3
.keyboardShortcut("C", modifiers: [.command, .shift])
}
}
// 4
func clearFavorites() {
let viewContext = PersistenceController.shared.container.viewContext
let batchUpdateRequest = NSBatchUpdateRequest(entity: Gem.entity())
batchUpdateRequest.propertiesToUpdate = ["favorite": false]
do {
try viewContext.execute(batchUpdateRequest)
} catch {
print("Handle Error: \(error.localizedDescription)")
}
}
}
代碼是這樣的:
- 1) 定義一個遵循
Commands
協(xié)議的新類型。 與View
協(xié)議一樣,此協(xié)議要求您實現(xiàn)某些命令的body
屬性。 - 2) 使用
CommandMenu
在狀態(tài)欄上定義菜單。 在CommandMenu
內(nèi)部,您可以定義一個按鈕來清除收藏夾。 - 3) 在按鈕上添加修飾符可添加鍵盤快捷鍵以執(zhí)行該操作。
keyboardShortcut(_:modifiers :)
具有兩個參數(shù):鍵盤快捷方式的String
和EventModifiers
的OptionSet
組合以觸發(fā)此快捷方式。 - 4) 定義清除收藏夾的方法。
返回AppMain.swift
并在WindowGroup
下添加以下代碼:
.commands { GemCommands() }
此修改器將命令添加到場景。 在macOS
上,它將命令添加到狀態(tài)欄。
在macOS
上構(gòu)建并運行。 收藏一些寶石,并使用鍵盤快捷鍵Command-Shift-C
清除它們。
做得好!
在本教程中,您學(xué)習(xí)了SwiftUI
如何使創(chuàng)建可在iOS,iPadOS
和macOS
上運行的多平臺應(yīng)用程序變得更加容易。 不僅如此,您還學(xué)習(xí)了如何在兩個平臺上重用視圖,以及如何在同一項目中為每個平臺創(chuàng)建自定義行為和UI。
蘋果公司承諾創(chuàng)建一個可在其所有平臺上運行的框架的承諾并沒有到此為止。 使用此項目,您可以創(chuàng)建應(yīng)用程序的watchOS
和tvOS
版本,同時共享相同的代碼庫。
要更深入地了解SwiftUI
的擴(kuò)展以及App
,Scenes
和Views
如何組合在一起,請從WWDC 2020
開始觀看App essentials in SwiftUI。如果您想繼續(xù)探索,本課程鏈接到一些相關(guān)視頻。
后記
本篇主要講述了基于SwiftUI和Xcode12的
Multiplatform App
的搭建,感興趣的給個贊或者關(guān)注~~~