SwiftUI:跨語(yǔ)言蜈彼、跨平臺(tái)、小組件

原創(chuàng):知識(shí)點(diǎn)總結(jié)性文章
創(chuàng)作不易俺驶,請(qǐng)珍惜幸逆,之后會(huì)持續(xù)更新,不斷完善
個(gè)人比較喜歡做筆記和寫總結(jié)暮现,畢竟好記性不如爛筆頭哈哈还绘,這些文章記錄了我的IOS成長(zhǎng)歷程,希望能與大家一起進(jìn)步
溫馨提示:由于簡(jiǎn)書不支持目錄跳轉(zhuǎn)栖袋,大家可通過command + F 輸入目錄標(biāo)題后迅速尋找到你所需要的內(nèi)容

目錄

  • 一拍顷、跨國(guó)應(yīng)用本地化
    • 1、商店描述
    • 2塘幅、UI 界面
    • 3昔案、應(yīng)用名稱
    • 4、交給別人翻譯
  • 二电媳、跨平臺(tái)應(yīng)用
    • 1踏揣、創(chuàng)建跨平臺(tái)應(yīng)用
    • 2、Mac 應(yīng)用版本間的差異
    • 3匾乓、區(qū)分 iPhone 及 Mac 平臺(tái)
    • 4捞稿、區(qū)分 iPadOS 及 iOS 平臺(tái)
    • 5、Apple Watch 應(yīng)用
    • 6拼缝、Apple TV 應(yīng)用
    • 7娱局、判斷 UI 在各平臺(tái)上的可用性
  • 三、桌面小組件 Widgets
    • 1咧七、背景
    • 2衰齐、系統(tǒng)級(jí)別的功能
    • 3、制作桌面小組件的流程
    • 4猪叙、代碼詳解

一娇斩、跨國(guó)應(yīng)用本地化

應(yīng)用本地化 Localization,主要指的是將現(xiàn)有應(yīng)用穴翩,根據(jù)不同地區(qū)的語(yǔ)言習(xí)慣翻譯為不同語(yǔ)種犬第。除此之外,它還意味著對(duì)當(dāng)?shù)氐氖褂昧?xí)慣進(jìn)行針對(duì)性調(diào)整芒帕,比如閱讀語(yǔ)序等歉嗓。SwiftUI 已經(jīng)自動(dòng)處理好了諸如文本框中的使用方向,導(dǎo)航器的呼出方向等問題背蟆,因此獨(dú)立開發(fā)者主要需要做的本例化工作便是翻譯鉴分。

在設(shè)計(jì)一款目標(biāo)發(fā)售地包含國(guó)際市場(chǎng)的應(yīng)用時(shí)哮幢,你需要?jiǎng)?wù)必留意所有字符串的長(zhǎng)度。中文作為一種用方塊文字表達(dá)意思的語(yǔ)言志珍,其簡(jiǎn)短的詞組便可以表達(dá)完整意思橙垢。而世界上很多語(yǔ)言是拉丁語(yǔ)系的,主要是用詞根和詞綴來對(duì)單詞進(jìn)行修飾伦糯,甚至在不少語(yǔ)言中物品還存在男女的叫法柜某,因此描述起來非常長(zhǎng)。比如某個(gè)單詞在中文中只需要兩個(gè)字符的位置敛纲,在德語(yǔ)中可能需要十幾個(gè)字符位喂击。

考慮到語(yǔ)言上的差異,在設(shè)計(jì)應(yīng)用程序界面時(shí)應(yīng)該留足空位淤翔,以便讓不同語(yǔ)言能完整顯示出來翰绊。對(duì)于界面元素,能用 SwiftUI 的就用旁壮,盡量避免直接從設(shè)計(jì)軟件中直接導(dǎo)入帶文字內(nèi)容的界面元素监嗜,這樣會(huì)給日后的本地化工作平添麻煩。

應(yīng)用程序的核心邏輯常不受語(yǔ)言限制寡具,將應(yīng)用翻譯為不同語(yǔ)言秤茅,十分有助于擴(kuò)展銷路。通常來說童叠,歐洲、美國(guó)课幕、中國(guó)這三大市場(chǎng)競(jìng)爭(zhēng)較為激烈厦坛,想要讓應(yīng)用獲得較好的排位相對(duì)困難。但競(jìng)爭(zhēng)激烈的同時(shí)乍惊,這些市場(chǎng)的回報(bào)也最高杜秸,值得為其所在地的語(yǔ)言進(jìn)行應(yīng)用翻譯工作。

對(duì)于較為小眾的市場(chǎng)润绎,諸如非洲或南亞各國(guó)撬碟,通常消費(fèi)力更低一些。Apple 本身的產(chǎn)品滲透率在這些地區(qū)也稍差莉撇,這時(shí)候能做到多少呢蛤,要做多少就得由你自己進(jìn)行取舍了。但有一點(diǎn)是確定的棍郎,市場(chǎng)再小也是市場(chǎng)其障,且這些小眾市場(chǎng)往往競(jìng)爭(zhēng)相對(duì)緩和,若你能對(duì)他們的語(yǔ)言進(jìn)行針對(duì)性優(yōu)化涂佃,成功的可能性反而更大些励翼。

本文將以支持「英文蜈敢、中文」的應(yīng)用為例差牛,介紹應(yīng)用本地化工作的方法丛塌。

1指厌、商店描述

應(yīng)用程序在 App Store 中的全部描述由 App Store Connect 網(wǎng)站負(fù)責(zé)附较。如下圖所示骗污,當(dāng)你希望添加不同語(yǔ)種的應(yīng)用簡(jiǎn)介何暮、更新公告時(shí)买猖,可以點(diǎn)擊下圖右側(cè)的語(yǔ)言按鈕询筏。選中語(yǔ)言過后膨蛮,點(diǎn)擊右側(cè)的「+」按鈕來新增應(yīng)用描述所支持的語(yǔ)言叠纹。

部分人只會(huì)翻譯應(yīng)用描述,卻忽略了預(yù)覽圖部分敞葛。若你在對(duì)主要的市場(chǎng)進(jìn)行翻譯工作時(shí)誉察,強(qiáng)烈建議一并更新預(yù)覽圖。假設(shè)不對(duì)預(yù)覽圖進(jìn)行單獨(dú)修改惹谐,則 App Store 會(huì)默認(rèn)使用默認(rèn)語(yǔ)言持偏,如英文的預(yù)覽圖在全球的商店顯示。

若你需要對(duì)預(yù)覽截圖進(jìn)行本地化氨肌,可以長(zhǎng)按應(yīng)用程序圖標(biāo)鸿秆,并選擇「Edit Scheme」。在彈出的下列界面中怎囚,找到「App Language 應(yīng)用語(yǔ)言」卿叽,將其修改為待截圖的目標(biāo)語(yǔ)言即可。

在 App Store Connect 的語(yǔ)言列表中恳守,你會(huì)看到某個(gè)語(yǔ)言帶有「Primary」標(biāo)識(shí)考婴,如下圖所示。在當(dāng)前應(yīng)用中催烘,Primary 語(yǔ)言指的是在開發(fā)者沒有提供對(duì)應(yīng)內(nèi)容的本地化翻譯時(shí)沥阱,任何素材、簡(jiǎn)介伊群、截圖等信息的默認(rèn)顯示語(yǔ)言考杉。

應(yīng)用名稱、標(biāo)題的翻譯在 App Store Connect 的「App Information 應(yīng)用信息」分區(qū)中舰始,如下圖所示崇棠。點(diǎn)擊右側(cè)的語(yǔ)言按鈕,可以在不同語(yǔ)言中切換蔽午。在上文中已添加中文易茬,因此下圖中也已經(jīng)包含了中文選項(xiàng)。切換至不同語(yǔ)言后,將翻譯填入下圖表格中即可抽莱。


2范抓、UI 界面

應(yīng)用啟動(dòng)后,顯示出的任何文字都可以說是 UI 界面的一部分食铐,翻譯這一部分內(nèi)容至關(guān)重要匕垫。在 Xcode 中依次選中「項(xiàng)目名 - Project 標(biāo)簽頁(yè)」,如下圖所示虐呻。下圖中包含一個(gè) Localization 的選項(xiàng)象泵,此處默認(rèn)情況下只有一個(gè)叫做 English - Development Language 的選項(xiàng),你可以把英文當(dāng)作代碼層面的默認(rèn)設(shè)置斟叼。想要添加新的語(yǔ)言支持偶惠,點(diǎn)擊「+」即可,本例中我選擇添加了簡(jiǎn)體中文 Simplified Chinese朗涩。

Xcode 對(duì) SwiftUI 中 UI 本地化流程有點(diǎn)像是查詢電話號(hào)碼本忽孽。該電話號(hào)碼本的文件類型為 Strings File。如下圖所示谢床,新建一個(gè) Strings File兄一。

將該文件命名為 Localizable.strings,代表 UI 翻譯文件识腿,之后點(diǎn)擊「Create」創(chuàng)建出革。

創(chuàng)建完成后,Xcode 會(huì)提供默認(rèn)英文版的電話號(hào)碼本渡讼,如下圖所示骂束。但我們還額外需要中文的電話號(hào)碼本,因此點(diǎn)擊下圖中右側(cè)的「Localize 本地化」按鈕硝全。

點(diǎn)擊 Localize 后栖雾,在下圖右側(cè)彈出的本地化選項(xiàng)中勾選英文和中文兩種語(yǔ)言。勾選完成后伟众,Xcode 會(huì)自動(dòng)在左側(cè)創(chuàng)建兩個(gè)號(hào)碼本,一個(gè)是英文版召廷,一個(gè)是中文版凳厢,如下圖所示。

在 SwiftUI 中竞慢,所有文本框中輸入的字符先紫,都會(huì)被 Xcode 視作是在號(hào)碼本中查詢的鑰匙。比如下圖的簡(jiǎn)單范例中筹煮,UI 是一個(gè)純文本視圖遮精,顯示「Three Good Things」,此時(shí) Three Good Things 便會(huì)被 Xcode 視作鑰匙拿去號(hào)碼本中查詢,如果號(hào)碼本中存在完全匹配的字符串本冲,則直接用號(hào)碼本中的翻譯准脂,如果沒有,則直接顯示 Three Good Things 這段未經(jīng)翻譯的文字檬洞。

想要讓 Xcode 知道這段話該如何翻譯狸膏,你需要依次進(jìn)入剛才創(chuàng)建好的中文和英文電話號(hào)碼本,依次輸入 Three Good Things 的翻譯方式添怔,如下圖所示湾戳,在中文的號(hào)碼本中 Three Good Things 會(huì)被翻譯為三件好事,英文的號(hào)碼本中會(huì)被翻譯為 Three Good Things 保持不變广料。值得注意的是砾脑,以中文翻譯「"Three Good Things" = "三件好事";」為例,等號(hào)左側(cè)的鑰匙必須要與 SwiftUI 中輸入的字符串完全匹配艾杏,等號(hào)右側(cè)的則是對(duì)應(yīng)的本地化翻譯韧衣,結(jié)束時(shí)必須用到英文分號(hào)「;」。

翻譯完成后糜颠,分別運(yùn)行中文版和英文版的虛擬機(jī)汹族,UI 效果如下。至此應(yīng)用的 UI 界面完成本地化翻譯其兴。


3顶瞒、應(yīng)用名稱

應(yīng)用名稱的翻譯與界面翻譯非常類似,不過需要?jiǎng)?chuàng)建一個(gè)專門用于查詢應(yīng)用顯示名稱的號(hào)碼本元旬。如下圖所示榴徐,新建一個(gè) Strings File

將該文件命名為「InfoPlist.strings」并創(chuàng)建文件匀归。

與上文類似坑资,點(diǎn)擊 Localize 按鈕將 Info.Plist 文件分別創(chuàng)建為兩種語(yǔ)言的號(hào)碼本。

打開對(duì)應(yīng)的語(yǔ)言文件并進(jìn)行翻譯穆端,比如「"CFBundleDisplayName" = "三件好事";」會(huì)將該應(yīng)用的中文顯示名稱改為「三件好事」袱贮。本例中,CFBundleDisplayName 指的是 Xcode 用于自動(dòng)識(shí)別應(yīng)用名稱的鑰匙体啰。

若你使用上述虛擬機(jī)切換語(yǔ)言的方法攒巍,會(huì)發(fā)現(xiàn)應(yīng)用的顯示名本地化沒有正確顯示。這是因?yàn)樵?iOS 設(shè)備時(shí)荒勇,所有應(yīng)用名稱不跟隨應(yīng)用自身設(shè)置柒莉,而是全部跟隨系統(tǒng)顯示,因此想要查看翻譯是否成功沽翔,需要在虛擬機(jī)的設(shè)置中兢孝,切換系統(tǒng)語(yǔ)言,如下圖中間的截圖所示,之后本地化應(yīng)用名稱即可正常顯示跨蟹。


4雳殊、交給別人翻譯

對(duì)于機(jī)器翻譯來說,我個(gè)人比較推薦 DeepL喷市,它的翻譯在水準(zhǔn)之上相种,且支持語(yǔ)言較多。筆者之前寫過一篇 介紹 DeepL 用法及效果的文章品姓,不再贅述寝并。但還有些情況,你可能會(huì)拜托朋友第三方翻譯幫你進(jìn)行本地化工作腹备,這時(shí)便需要把文件交給別人衬潦,這時(shí)便需要分享源文件。打開 Xcode植酥,并右鍵選擇「Show in Finder」镀岛。

在打開的 Xcode 項(xiàng)目中,你會(huì)看到尾綴是 .lproj 的本地化翻譯文件友驮。比如 en 指的就是英文翻譯漂羊,zh-Hans 指的是中文翻譯。假設(shè)你希望請(qǐng)別人翻譯英文版卸留,只需要把 en.lproj 文件夾分享給他人即可走越,不需要分享整個(gè) Xcode 項(xiàng)目文件。

以中文為例耻瑟,本地化文件夾中包含 InfoPlist.strings 應(yīng)用名稱文件旨指,以及 Localizable.strings 應(yīng)用 UI 文件。若對(duì)方的機(jī)器是 Windows喳整,或沒有 Xcode 的 Mac谆构,你可以請(qǐng)對(duì)方用任意的文本編輯器打開進(jìn)行翻譯。以 Mac 為例框都,右鍵打開該文件搬素,選擇用自帶的文本編輯器「TextEdit」打開即可。

打開后的文件如下圖所示魏保,修改好翻譯之后保存蔗蹋。當(dāng)開發(fā)者拿到翻譯完的文件夾后,直接粘貼到 Xcode 項(xiàng)目中覆蓋舊的翻譯文件夾即可囱淋。


二、跨平臺(tái)應(yīng)用

隨著 Mac 產(chǎn)品線逐漸過渡到 M 系列芯片餐塘,SwiftUI 轉(zhuǎn)變成為 Apple 生態(tài)系統(tǒng)中全部平臺(tái)的主要 UI 語(yǔ)言妥衣,跨平臺(tái)應(yīng)用開發(fā)變得前所未有地簡(jiǎn)單。對(duì)于開發(fā)者來說,使用 SwiftUI 的標(biāo)準(zhǔn)控件税手,可以讓你無(wú)需操心如何定制適用于各個(gè)平臺(tái)的 UI蜂筹,只需要用一套寫法,在每個(gè)系統(tǒng)平臺(tái)中都會(huì)自動(dòng)適配相應(yīng)的 UI 外觀芦倒。

1艺挪、創(chuàng)建跨平臺(tái)應(yīng)用

若你只需要某個(gè)平臺(tái)的應(yīng)用,可以直接選擇對(duì)應(yīng)的「iOS」或「macOS」應(yīng)用模版進(jìn)行創(chuàng)建兵扬。若你想創(chuàng)建跨 iPad麻裳、iOS、macOS 三平臺(tái)應(yīng)用器钟,只需要在 Xcode 創(chuàng)建應(yīng)用的模版中選擇「Multiplatform - App」即可津坑,如下圖所示。

跨三平臺(tái)的應(yīng)用默認(rèn)使用 SwiftUI 作為 UI 界面語(yǔ)言傲霸,使用 SwiftUI Lifecycle 用作生命周期控制疆瑰,無(wú)任何使用其它選擇,如下圖所示昙啄。


2穆役、Mac 應(yīng)用版本間的差異

未來數(shù)年中,會(huì)出現(xiàn)英特爾芯片與 M 系列 Mac 機(jī)型并存的狀態(tài)梳凛,因此 Mac 版本和運(yùn)作方式稍顯復(fù)雜耿币。創(chuàng)建完跨平臺(tái)應(yīng)用后,你會(huì)注意到應(yīng)用運(yùn)行窗口有兩個(gè)選項(xiàng)伶跷,其中之一備注為 iOS掰读,其二備注為 macOS。

這里有個(gè)選項(xiàng)你也許會(huì)覺得奇怪叭莫,在 iOS 大類中蹈集,居然出現(xiàn)了 My Mac (Designed for iPad) 選項(xiàng)。這個(gè)選項(xiàng)指的是該應(yīng)用仍然為 iOS 應(yīng)用雇初,若開發(fā)者不進(jìn)行額外說明拢肆,默認(rèn)支持所有搭載 M 芯片的 Mac 電腦運(yùn)行。本質(zhì)上來說靖诗,以該模式運(yùn)行的應(yīng)用仍然為原版的 iOS 應(yīng)用郭怪。在此模式下,所有 UI 顯示方式和操作手勢(shì)等完全與 iOS 版本相同刊橘。

在 macOS 應(yīng)用的選項(xiàng)中鄙才,出現(xiàn)了兩個(gè) Mac 對(duì)應(yīng)類型,分別是 My MacMy Mac (Rosetta)促绵,均指的是以 Mac 版本的 UI 進(jìn)行顯示攒庵。若你正在使用的 Mac 開發(fā)機(jī)器搭載 M1 芯片嘴纺,則 My Mac 指的是讓應(yīng)用以 x86 原生模式運(yùn)行;若你正在使用的 Mac 開發(fā)機(jī)器搭載 M1 芯片浓冒,則 My Mac 指的是讓應(yīng)用以 ARM 原生模式運(yùn)行栽渴。在 M1 版本的機(jī)器上,還會(huì)額外出現(xiàn) Rosetta 的選項(xiàng)稳懒,指的是應(yīng)用以 x86 形式編譯闲擦,通過兼容層在 M 芯片的機(jī)器上運(yùn)行。

若你在應(yīng)用中用到了較老的 UIKit 作為視圖框架墅冷,還可能在運(yùn)行欄中看到 My Mac (Catalyst)辙谜,指的是將 UIKit 應(yīng)用以 MacCatalyst 翻譯后,運(yùn)行在 Mac 機(jī)型中装哆。請(qǐng)注意罐脊,以上所有的選項(xiàng)蜕琴,均取決于你的開發(fā)機(jī)器,可能和本文截圖有所差異凌简∩涎祝總的來說,現(xiàn)階段下 Mac 應(yīng)用運(yùn)行共有 6 種方式藕施,分別是:

  • Mac (Designed for iPad):純 iOS 應(yīng)用裳食,僅支持 M 芯片版 Mac
  • Mac (Intel):純 macOS 應(yīng)用芙沥,僅支持 Intel 芯片版 Mac
  • Mac (ARM):純 macOS 應(yīng)用,僅支持 M 芯片版 Mac
  • Mac (Rosetta):純 macOS 應(yīng)用救氯,支持 M 及 Intel 芯片版 Mac
  • Mac (Catalyst):較老的寫法歌憨。純 Mac 版 UIKit 應(yīng)用务嫡,支持 M 及 Intel 芯片版 Mac
  • Mac (Appkit):較老的寫法底桂。純 Appkit 應(yīng)用,支持 M 及 Intel 芯片版 Mac

3于个、區(qū)分 iPhone 及 Mac 平臺(tái)

你也許會(huì)問厅篓,同樣的代碼,假設(shè)我需要?jiǎng)?chuàng)建出兩種不同的視圖排版怎么辦或链。遇到特別復(fù)雜的界面差異档押,你可以考慮新建一個(gè) SwiftUI 視圖令宿,來單獨(dú)處理某個(gè)平臺(tái)的顯示。若你只需要進(jìn)行一些細(xì)微變動(dòng)粒没,則可以使用語(yǔ)法 #if os(xxx) #endif 來進(jìn)行針對(duì)性判斷癞松。如下圖所示,如果軟件運(yùn)行在 iOS 設(shè)備上硕勿,則顯示 iOS 文字厕妖,反之則顯示 macOS 文字言秸。

將包含上述代碼所示的應(yīng)用運(yùn)行后,結(jié)果如下查排“虾耍可以看到,雖然是同一個(gè) SwiftUI 視圖蹋订,內(nèi)容根據(jù)平臺(tái)進(jìn)行了差異化顯示露戒。


4捶箱、區(qū)分 iPadOS 及 iOS 平臺(tái)

Apple 當(dāng)下的生態(tài)系統(tǒng)命名有些不規(guī)范丁屎,雖然 iPad 上設(shè)備名義上運(yùn)行的是 iPadOS 操作系統(tǒng),但是在 Xcode 體系中证九,仍然被歸類為 iOS甫贯。因此上述判斷方案無(wú)法得知應(yīng)用是運(yùn)行在 iPhone 還是 iPad 上看蚜。此時(shí)可以用到另一種判斷方法供炎,如果 UIDevice.current.userInterfaceIdiom == .pad 為真,則運(yùn)行在 iPad 上惨奕,反之運(yùn)行在 iPhone 上梨撞,如下圖所示香罐。

運(yùn)行上述代碼后庇茫,效果如下圖所示〔槠海可以看到 iOS 和 iPadOS 的代碼被區(qū)分看待偿曙。


5、Apple Watch 應(yīng)用

若你希望給應(yīng)用增加 Apple Watch 的手表支持覆醇,可以在 Xcode 頂部菜單欄中,選擇「File - New Target」鞋仍,如下圖所示搅吁。

在 watchOS 菜單中谎懦,可以看到「Watch App for iOS App」和「Watch App」兩個(gè)選項(xiàng)。這二者的區(qū)分度需要額外留意吸申,其中 for iOS App 指的是該手表應(yīng)用必須依賴于 iOS 應(yīng)用主體發(fā)布截碴,無(wú)法單獨(dú)在 Watch 應(yīng)用商店中下載日丹。無(wú)論該手表應(yīng)用是否存在與 iOS 應(yīng)用的數(shù)據(jù)互通蚯嫌,這種依賴關(guān)系是必須存在的择示。而 Watch App 指的是可以單獨(dú)發(fā)布,無(wú)需依賴任何 iOS 應(yīng)用湘今,可直接在 Watch 應(yīng)用商店中下載的應(yīng)用摩瞎。這二者根據(jù)你的實(shí)際需求選擇即可。

選擇完成后蚓哩,如下圖所示岸梨,將 Watch 應(yīng)用添加至 Xcode 項(xiàng)目中曹阔。

添加完成后隔披,若你選擇的是 Watch App for iOS App 選項(xiàng)奢米,則會(huì)看到下圖左側(cè)多出來了 WatchApp Extension 選項(xiàng)。該文件夾中的內(nèi)容谒拴,是 Xcode 已經(jīng)為 Watch 應(yīng)用創(chuàng)建好的模版英上。以我們熟悉的 ContentView.swift 為例善延,可以看到如下圖所示的 SwiftUI 視圖代碼城侧。

額外說明一下嫌佑,你也許會(huì)感到疑惑,Xcode 如何知道項(xiàng)目中相同文件名的文件到底該運(yùn)行哪一份揩魂,答案是 Target Membership 運(yùn)行目標(biāo)火脉。如下圖右側(cè)所示倦挂,假設(shè)代碼的核心邏輯下載在 Logic.swift 文件中,倘若在右側(cè)面板勾選 WatchApp Extension没炒,則代表這份文件可以在 Watch 應(yīng)用中使用送火,其它所有文件同理种吸,都具備運(yùn)行目標(biāo)這個(gè)選項(xiàng)呀非。

結(jié)束界面和邏輯的編程后姜钳,點(diǎn)擊運(yùn)行欄中的 WatchApp哥桥,并在模擬器中選擇一臺(tái)虛擬機(jī)即可運(yùn)行激涤。額外說明的是倦踢,若你希望用到真機(jī)測(cè)試辱挥,則需要在 Xcode 中的「Window - Devices and Simulators」中晤碘,對(duì)手表進(jìn)行與手機(jī)的配對(duì)。之后就可以直接在真機(jī)手表上進(jìn)行測(cè)試了宠蚂。

將 Watch 虛擬機(jī)一并運(yùn)行求厕,當(dāng)前版本的跨平臺(tái)應(yīng)用已支持 iPad呀癣、iPhone、Apple Watch抵代、Mac 這四個(gè)平臺(tái)荤牍。


6康吵、Apple TV 應(yīng)用

在海外市場(chǎng)中访递,Apple TV 應(yīng)用也占據(jù)一席之地拷姿。你可以將 TV 應(yīng)用理解為家庭機(jī)頂盒响巢,或運(yùn)行在智能電視中的應(yīng)用,只不過在 Apple 平臺(tái)的硬件載體是 Apple TV含长。重復(fù)上述 Apple Watch 應(yīng)用的添加方法拘泞,這次選擇 TV App 即可創(chuàng)建 Apple TV 應(yīng)用陪腌。創(chuàng)建完成后偷厦,點(diǎn)擊 Apple TV 模擬機(jī)即可運(yùn)行燕刻,如下圖所示卵洗。

至此,在同一個(gè) Xcode 項(xiàng)目中添加各平臺(tái)的代碼介紹完畢聚至,如下圖所示扳躬。Mac甚亭、Apple TV亏狰、Apple Watch暇唾、iPhone、iPad 應(yīng)用均通過 SwiftUI 界面語(yǔ)言串聯(lián)在一起瘸味。


7硫戈、判斷 UI 在各平臺(tái)上的可用性

在開發(fā)過程中,你也許會(huì)碰到另一個(gè)問題梭姓,我的 SwiftUI 代碼到底哪些可以用誉尖。這個(gè)問題的答案寫在 Apple 開發(fā)者文檔中铡恕,如下圖右側(cè)所示丢间,在調(diào)用框架時(shí)烘挫,你需要注意該框架中內(nèi)容的可用性。比如 Toggle 開關(guān)的寫法苛蒲,支持全平臺(tái)使用臂外。如下圖所示漏健,將一個(gè)最簡(jiǎn)單的開關(guān)代碼放置在跨平臺(tái)文件夾中无牵。

@State private var toggleOn = true 
Toggle("Do Something", isOn: $toggleOn).padding()

對(duì)于視圖有差異的 Apple TV茎毁,同理將開關(guān)代碼復(fù)制進(jìn)去,但刪除 iOS 的判斷語(yǔ)句谭溉。

準(zhǔn)備完成后運(yùn)行橡卤,可以看到如下圖所示的界面碧库。在 Mac嵌灰、iPhone沽瞭、Apple Watch驹溃、Apple TV 中豌鹤,同樣的 SwiftUI 開關(guān)寫法,實(shí)際上顯示方式完全不一樣磺平。在 Mac 中是我們熟悉的勾選框拣挪,而在 TV 中則是點(diǎn)入式菜單菠劝。這也是 SwiftUI 強(qiáng)大的地方赶诊,并非追求統(tǒng)一舔痪,而是在代碼統(tǒng)一的前提下锄码,保證各個(gè)平臺(tái)體驗(yàn)的獨(dú)立性滋捶。

對(duì)于很多應(yīng)用來說重窟,諸如用到 Apple Pencil 的 Procreate巡扇,也許純 iPad 應(yīng)用就已經(jīng)是最佳選擇厅翔;對(duì)于筆記應(yīng)用如 Bear,用戶確實(shí)有跨平臺(tái)記錄的需求;對(duì)于一款快速查看潮汐的應(yīng)用涩赢,也許純 Apple Watch 應(yīng)用已經(jīng)是最佳選擇筒扒,畢竟在進(jìn)行這類運(yùn)動(dòng)時(shí)用戶手機(jī)大概不在身邊花墩。


三冰蘑、桌面小組件 Widgets

桌面小組件 Widget 是 iOS 14祠肥、macOS Big Sur 之后仇箱,Apple 推出的顯示在桌面上的便捷視圖〖燎牛現(xiàn)階段权逗,桌面小組件可以被用在 iPhone旬迹、iPad奔垦、Mac 這三類設(shè)備中椿猎。Apple 生態(tài)系統(tǒng)中的小組件以展示信息為核心訴求犯眠,僅提供非常輕量的互動(dòng)筐咧。若你習(xí)慣了 Android 手機(jī)上的部分復(fù)雜強(qiáng)大的桌面組件量蕊,應(yīng)該適當(dāng)降低預(yù)期残炮,Apple 版本的桌面小組件與其還是有較大差異的势就。

1、背景

以 iPhone 為例袖牙,小組件主要集中在設(shè)備的負(fù)一屏侧巨,亦可被添加在桌面的任意位置。當(dāng)用戶長(zhǎng)按桌面背景贼陶,并點(diǎn)擊左上角的加號(hào)后刃泡,可以看到如下圖所示的小組件選擇器。小組件選擇器羅列了當(dāng)前設(shè)備中所有支持的小組件的應(yīng)用碉怔,并提供了小組件預(yù)覽烘贴,用戶點(diǎn)擊后即可拖拽添加至桌面撮胧。

小組件分為三種尺寸桨踪,分別是占據(jù) 4 個(gè)應(yīng)用圖標(biāo)格的小尺寸、8 個(gè)應(yīng)用圖標(biāo)格的中尺寸芹啥、16 個(gè)應(yīng)用圖標(biāo)格的大尺寸锻离。值得注意的是:對(duì)于小尺寸的桌面小組件來說,除自身顯示的信息外墓怀,其本質(zhì)上就僅僅是一個(gè)按鈕汽纠。開發(fā)者無(wú)法自定義任何小組件中的互動(dòng)模塊,除展示信息外其功能只有一個(gè)傀履,就是點(diǎn)擊后跳轉(zhuǎn)到哪里去虱朵。而中號(hào)或者大號(hào)應(yīng)用小組件,則支持稍多一些的互動(dòng)選項(xiàng)钓账,允許開發(fā)者提供多個(gè)按鈕碴犬。


2、系統(tǒng)級(jí)別的功能

WidgetKit 是純 SwiftUI 視圖的框架梆暮。得益于 SwiftUI 及諸多系統(tǒng)內(nèi)置的功能服协,在開發(fā)者什么都不做的前提下,小組件自身已經(jīng)具備了幾項(xiàng)常用功能啦粹。本小節(jié)用「自動(dòng)暗色模式」和「小組件推薦輪轉(zhuǎn)」舉例偿荷。

如下圖所示,當(dāng)設(shè)備從淺色模式切換至深色模式時(shí)唠椭,界面中的黃色做出了輕微的版本調(diào)整跳纳。所有字體的和背景的顏色也進(jìn)行了反轉(zhuǎn),比如 Steve's Surprise Party 從黑色切換到了白色泪蔫。對(duì)于這些設(shè)置,只要你的視圖代碼中用到了類似 .color(.primary) 這樣的標(biāo)準(zhǔn)寫法喘批,或用到了系統(tǒng)提供的標(biāo)準(zhǔn)色撩荣,以上特性都是自動(dòng)白送的铣揉。

如下圖所示,用戶可以將多個(gè)小組件疊加在一起餐曹,成為一個(gè)堆疊 Stack逛拱。 對(duì)于堆疊在一起的小組件來說,系統(tǒng)會(huì)使用基于 On-Device Intelligence 本地智能的機(jī)器學(xué)習(xí) + 推薦算法台猴,來決定在某個(gè)時(shí)刻朽合,哪一個(gè)小組件會(huì)在屏幕的最上方。其數(shù)據(jù)來源主要是小組件的 Donation 捐贈(zèng)饱狂,舉個(gè)例子曹步,倘若在廈門的用戶在早上 8:30 分的時(shí)候查看了天氣,那么天氣應(yīng)用很可能捐贈(zèng)了一個(gè)「8:30 查看廈門天氣」的事件休讳。當(dāng)捐贈(zèng)形成規(guī)律后讲婚,系統(tǒng)會(huì)將這些捐贈(zèng)當(dāng)作一個(gè)新知識(shí),下次 8:30 分時(shí)自動(dòng)將天氣小組件前置俊柔。


3筹麸、制作桌面小組件的流程

在 Xcode 中新增小組件的流程與新增 watchOS 應(yīng)用的流程非常相似,都需要新增一個(gè) Target雏婶。如下圖所示物赶,在頂部的菜單欄中選擇「File - New -Target」。

在彈出的選項(xiàng)中留晚,選擇「iOS」酵紫。接著在「Application Extension」中找到「Widget Extension」并點(diǎn)擊下一步。

此處彈出的是小組件在開發(fā)期間的名稱倔丈,根據(jù)你的喜好起名即可憨闰,不得與項(xiàng)目名重復(fù)。本例中需五,使用 WidgetTarget 作為名稱鹉动,如下圖所示。

完成以上步驟后宏邮,Xcode 會(huì)新建幾份模版文件泽示,其中之前沒見過的文件類型是:WidgetTarget.swiftWidgetTarget.intentdefinitions。在什么內(nèi)容都不添加的情況下蜜氨,該模版文件已經(jīng)準(zhǔn)備好了一個(gè)時(shí)鐘應(yīng)用械筛,直接運(yùn)行后如下圖所示,顯示當(dāng)前時(shí)間飒炎。本文會(huì)專注講解這個(gè)時(shí)鐘應(yīng)用模版中各類代碼的用途埋哟。

在上圖中,你也許注意到了系統(tǒng)的實(shí)際時(shí)間是 6:59,而小組件顯示時(shí)間是 6:56赤赊,這是因?yàn)樾〗M件的更新不是即時(shí)的闯狱,而是由系統(tǒng)根據(jù)開發(fā)者提供的時(shí)間軸來盡量安排。


4抛计、代碼詳解

上述流程走完后哄孤,Xcode 模版會(huì)自動(dòng)生成的 WidgetTarget.swift 文件,如下圖所示吹截。

此處的 WidgetTarget.swift 文件名瘦陈,與之前創(chuàng)建 Widget 時(shí)空格中填寫的命名一致。因每個(gè)人的命名可能不同波俄,你的文件可能不叫 WidgetTarget晨逝,但內(nèi)容是一致的,不必?fù)?dān)心弟断。本例中咏花,我將以 WidgetTarget 這個(gè)命名為例子。

WidgetTarget.swift 文件中包含五個(gè)重要的結(jié)構(gòu)體 struct阀趴,分別是:Provider昏翰、SimpleEntryWidgetTargetEntryView刘急、WidgetTarget棚菊、WidgetTarget_Previews。這些概念相對(duì)較新叔汁,大多是 2020 年之后 Apple 發(fā)布的 WidgetKit 中提到的全新概念统求,因此我會(huì)在下文亂序進(jìn)行逐一解析。

如下圖所示据块,WidgetTargetEntryView 結(jié)構(gòu)對(duì)應(yīng)的是標(biāo)準(zhǔn)的 SwiftUI 視圖码邻。其中與視圖有關(guān)的代碼寫在 var body: some View { } 中。如下圖所示另假,Text(entry.date, style: .time) 指的是用 date 這個(gè)時(shí)間戳用于數(shù)據(jù)來源像屋,并將其以 time 時(shí)鐘的方式顯示出來,是一個(gè) Text 純文本視圖边篮。

你也許會(huì)好奇己莺,傳遞數(shù)據(jù)的信息是從哪里來的,答案是 SimpleEntry 這個(gè)結(jié)構(gòu)體戈轿。如下圖所示凌受,SimpleEntry 繼承了一個(gè)名為 TimelineEntry 的協(xié)議。對(duì)于小組件來說思杯,存在一個(gè)重要的時(shí)間軸 Timeline 的概念 胜蛉,對(duì)于組件的任何一個(gè)時(shí)刻,系統(tǒng)需要知道組件想顯示什么內(nèi)容,并根據(jù)組件的時(shí)間軸進(jìn)行排期誊册。比如一個(gè)日歷應(yīng)用奈梳,很可能每天在三個(gè)時(shí)間點(diǎn)各更新一次,每次對(duì)應(yīng)的時(shí)間的信息都不同解虱,每一個(gè)時(shí)間點(diǎn)的信息片段,都存在 SimpleEntry 中漆撞。

如下圖所示殴泰,WidgetTargetWidgetTarget_Previews 這兩個(gè)結(jié)構(gòu)體負(fù)責(zé)視圖的顯示和 Xcode 窗口預(yù)覽。其中 WidgetTarget_Previews 就不多說了浮驳,只是單純地提供該小組件的 Canvas 預(yù)覽窗口悍汛,與實(shí)際允許在設(shè)備中的代碼無(wú)關(guān)。.previewContext(WidgetPreviewContext(family: .systemSmall)) 是個(gè)新的修改器至会,指的是用小尺寸的小組件來預(yù)覽离咐。

上圖中 @main 指的是小組件應(yīng)用的接入點(diǎn)。其中 WidgetTargetEntryView(entry: entry) 負(fù)責(zé)把上文中定義的 SwiftUI 視圖 WidgetTargetEntryView 代入最新數(shù)據(jù)并顯示奉件。值得額外介紹的是兩個(gè)新的修改器宵蛀,此處 .configurationDisplayName("My Widget") 指的是小組件選擇界面的組件名稱,.description("This is an example widget.") 指的是小組件描述县貌,對(duì)應(yīng)內(nèi)容如下圖所示术陶。

最后值得一提的新內(nèi)容便是 Provider 這個(gè)結(jié)構(gòu)體,如下圖所示煤痕,繼承了 IntentTimelineProvider梧宫。顧名思義,Provider 是一個(gè)提供者摆碉,負(fù)責(zé)由小組件向操作系統(tǒng)提供信息塘匣。這個(gè)協(xié)議來要求開發(fā)者提供三個(gè)必備函數(shù),分別是 placeholder巷帝、getSnapshotgetTimeline忌卤。

getPlaceholder 的用途是在沒有網(wǎng)絡(luò)連接,或數(shù)據(jù)還沒能及時(shí)加載的情況下锅睛,小組件接收到的默認(rèn)的信息埠巨。這一部分信息可以由開發(fā)者直接提供,以淘寶為例现拒,貨物信息默認(rèn)可以是「精選商品」辣垒,運(yùn)輸信息可以是「已經(jīng)在路上」。

getSnapshot 則是在諸如小組件選擇界面印蔬,屏幕上真實(shí)展示的小組件中勋桶,顯示的具備真實(shí)信息的內(nèi)容。舉個(gè)例子,假設(shè)現(xiàn)在是 10:00 分例驹,則 getSnapshot 返回的便是具備 10:00 這個(gè)信息的小組件狀態(tài)捐韩。

getTimeline 指的是操作系統(tǒng)向小組件索要的時(shí)間軸。系統(tǒng)需要知道桌面顯示出來的每個(gè)組件鹃锈,需要在什么時(shí)候進(jìn)行數(shù)據(jù)更新荤胁。比如你的小組件顯示的內(nèi)容只是每日精選書摘,那么時(shí)間軸中的內(nèi)容便是「每日更新一次」這個(gè)時(shí)間屎债。系統(tǒng)會(huì)根據(jù)這個(gè)頻率來對(duì)組件內(nèi)容進(jìn)行更新仅政。

請(qǐng)注意,在時(shí)間軸函數(shù)中盆驹,開發(fā)者給出的時(shí)間軸只是告訴系統(tǒng)我希望你按照這個(gè)標(biāo)準(zhǔn)刷新小組件圆丹。但系統(tǒng)并不保證執(zhí)行,因此這只是君子協(xié)議躯喇,實(shí)際刷新時(shí)間由系統(tǒng)根據(jù)當(dāng)前電量辫封、顯示在最上層的組件等信息決定碘耳。

上圖中的文件 WidgetTarget.intentdefinition绍移,作用是為小組件提供更復(fù)雜的自定義功能。這一部分內(nèi)容對(duì)于新人有些超綱了药蜻,因?yàn)樗婕傲艘恍╆P(guān)于 SiriKit的知識(shí)正压,本教程不做額外擴(kuò)展講解璃诀。

以上知識(shí)可以帶你入門,卻不足以憑此構(gòu)建一個(gè)復(fù)雜的小組件應(yīng)用蔑匣。若你對(duì)創(chuàng)建復(fù)雜桌面小組件感興趣劣欢,強(qiáng)烈推薦以下 WWDC 開發(fā)者大會(huì)視頻。

桌面小組件算是過去數(shù)年中裁良,能帶來明顯用戶感知的新系統(tǒng)特性凿将。其核心目的在于展示信息,并非提供深層次互動(dòng)价脾。你可以圍繞該目的牧抵,去思考應(yīng)用中哪些信息適合以小組件的形式呈現(xiàn)出來。與此同時(shí)侨把,若你的應(yīng)用的確需要的是復(fù)雜的互動(dòng)犀变,直接考慮完整應(yīng)用會(huì)更合適一些,切忌把復(fù)雜邏輯交給注重「輕量」的小組件秋柄。


Demo

Demo在我的Github上获枝,歡迎下載。
SwiftUIDemo

從零開始實(shí)操完整的小組件項(xiàng)目
小組件設(shè)計(jì)
視圖構(gòu)建及自定義

參考文獻(xiàn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
禁止轉(zhuǎn)載骇笔,如需轉(zhuǎn)載請(qǐng)通過簡(jiǎn)信或評(píng)論聯(lián)系作者省店。
  • 序言:七十年代末嚣崭,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子懦傍,更是在濱河造成了極大的恐慌雹舀,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,185評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件粗俱,死亡現(xiàn)場(chǎng)離奇詭異说榆,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)寸认,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,445評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門娱俺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人废麻,你說我怎么就攤上這事∧B” “怎么了烛愧?”我有些...
    開封第一講書人閱讀 157,684評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)掂碱。 經(jīng)常有香客問我怜姿,道長(zhǎng),這世上最難降的妖魔是什么疼燥? 我笑而不...
    開封第一講書人閱讀 56,564評(píng)論 1 284
  • 正文 為了忘掉前任沧卢,我火速辦了婚禮,結(jié)果婚禮上醉者,老公的妹妹穿的比我還像新娘但狭。我一直安慰自己,他們只是感情好撬即,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,681評(píng)論 6 386
  • 文/花漫 我一把揭開白布立磁。 她就那樣靜靜地躺著,像睡著了一般剥槐。 火紅的嫁衣襯著肌膚如雪唱歧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,874評(píng)論 1 290
  • 那天粒竖,我揣著相機(jī)與錄音颅崩,去河邊找鬼。 笑死蕊苗,一個(gè)胖子當(dāng)著我的面吹牛沿后,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播朽砰,決...
    沈念sama閱讀 39,025評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼得运,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼膝蜈!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起熔掺,我...
    開封第一講書人閱讀 37,761評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤饱搏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后置逻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體推沸,經(jīng)...
    沈念sama閱讀 44,217評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,545評(píng)論 2 327
  • 正文 我和宋清朗相戀三年券坞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鬓催。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,694評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡恨锚,死狀恐怖宇驾,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情猴伶,我是刑警寧澤课舍,帶...
    沈念sama閱讀 34,351評(píng)論 4 332
  • 正文 年R本政府宣布,位于F島的核電站他挎,受9級(jí)特大地震影響筝尾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜办桨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,988評(píng)論 3 315
  • 文/蒙蒙 一筹淫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧呢撞,春花似錦损姜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,778評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至脓鹃,卻和暖如春逸尖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瘸右。 一陣腳步聲響...
    開封第一講書人閱讀 32,007評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工娇跟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人太颤。 一個(gè)月前我還...
    沈念sama閱讀 46,427評(píng)論 2 360
  • 正文 我出身青樓苞俘,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親龄章。 傳聞我的和親對(duì)象是個(gè)殘疾皇子吃谣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,580評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容