Lesson 1:創(chuàng)建一個(gè)基本的UI

這節(jié)課將會(huì)讓你對(duì)Xcode以及它里面你用來寫app的工具更加熟悉。你將會(huì)學(xué)到一個(gè)Xcode項(xiàng)目的基本架構(gòu)并學(xué)會(huì)如何使用基本項(xiàng)目組件構(gòu)建一個(gè)互相跳轉(zhuǎn)的app。在這節(jié)課中,你會(huì)為FoodTracker app創(chuàng)建一個(gè)簡(jiǎn)單的用戶交互(UI)并可以在模擬器中進(jìn)行查看。當(dāng)你結(jié)束時(shí),你的app將會(huì)擁有如下元件:一個(gè)表示美食名稱的文本,一個(gè)輸入框用來輸入你自定義的美食名稱,以及一個(gè)按鈕來觸發(fā)修改美食名稱事件。


頁面成品圖

學(xué)習(xí)目標(biāo):

學(xué)習(xí)完這個(gè)課程,你要讓你自己掌握如下要點(diǎn)。

1、在Xcode上創(chuàng)建一個(gè)項(xiàng)目

2、明白示例項(xiàng)目中所有文件創(chuàng)建的目的

3、開關(guān)一個(gè)項(xiàng)目中的文件

4、在storyboard上添加、移動(dòng)和重新設(shè)置UI

5、在storyboard中使用屬性檢查器來對(duì)UI進(jìn)行調(diào)整和設(shè)置

6、使用大綱視圖進(jìn)行查看并調(diào)整UI

7、使用助理編輯的預(yù)覽模式來預(yù)覽UI

8、使用Auto Layout來布置UI使得它可以自適應(yīng)用戶的設(shè)備尺寸

如何創(chuàng)建Project就不說了,這個(gè)無需翻譯,直接進(jìn)入后面的布局和開發(fā)階段。

不過在此做個(gè)記錄,創(chuàng)建project時(shí)出現(xiàn)這個(gè)頁面:

創(chuàng)建頁面

這個(gè)頁面中最后3個(gè),一般都不用勾選,而Unit test(第二個(gè))是單元測(cè)試,是為了從小功能就檢驗(yàn)代碼的正確,保證項(xiàng)目的正確。勾選后,在project file中創(chuàng)建一個(gè)tests文件。

查看源代碼

AppDelegate.swift源代碼文件

AppDelegate.swift有兩個(gè)主要功能:

1、他定義了一個(gè)叫做AppDelegate的類,委托app創(chuàng)建了一個(gè)窗口,用于展現(xiàn)你app的內(nèi)容并提供一個(gè)地方可以響應(yīng)app的狀態(tài)改變(比如active、background等)。

2、他創(chuàng)建了一個(gè)app的入口和一個(gè)傳遞進(jìn)入事件的運(yùn)行循環(huán)給你的app。上述工作是UIApplicationMain 中的屬性。由文件的首行代碼 @UIApplicationMain 來實(shí)現(xiàn)。

使用UIApplicationMain 屬性其實(shí)等于調(diào)起UIApplicationMain 函數(shù)并把AppDelegate類的名稱作為輸入類型傳給它(UIApplicationMain 函數(shù)),然后系統(tǒng)會(huì)創(chuàng)建一個(gè)應(yīng)用對(duì)象,這個(gè)對(duì)象負(fù)責(zé)管理整個(gè)app的生命周期。系統(tǒng)也會(huì)創(chuàng)建AppDelegate類的實(shí)力,并把它和應(yīng)用對(duì)象關(guān)聯(lián)起來,最終,系統(tǒng)啟動(dòng)你的app。

AppDelegate會(huì)在你創(chuàng)建一個(gè)新項(xiàng)目時(shí)自動(dòng)創(chuàng)建,你需要用這個(gè)類提供你的app的初始化并響應(yīng)app總層面上的事件。這個(gè)AppDelegate遵守UIApplicationDelegate協(xié)議,這個(gè)協(xié)議定義了一系列的方法用于建立你的app;反饋app狀態(tài)的改變,或處理其他應(yīng)用級(jí)的事件。

AppDelegate類包含一個(gè)屬性:window

這個(gè)屬性存儲(chǔ)對(duì)app窗口的引用,它表現(xiàn)為你app中的各級(jí)view層的根屬性。也是你app所有內(nèi)容繪制的地方,注意,這個(gè)window的type是optional。即在某些時(shí)候可能為空(nil)

AppDelegate.swift源代碼文件包含這些函數(shù):

1、application(_:didFinishLaunchingWithOptions:)函數(shù)

application函數(shù)

使用這個(gè)方法(以及孿生方法application(_:willFinishLaunchingWithOptions:)),兩者一起來完成你的app的初始化并進(jìn)行最終的調(diào)整。這個(gè)方法會(huì)在狀態(tài)指令(下面的一些did指令)發(fā)起后,app屏幕和UI展示之前進(jìn)行調(diào)用。這個(gè)方法調(diào)用后,系統(tǒng)才會(huì)調(diào)用其他delegate方法(下面幾種)去讓app進(jìn)入活躍狀態(tài)或進(jìn)入后臺(tái)狀態(tài)。

如果你不在application(_:willFinishLaunchingWithOptions:)方法中進(jìn)行修改launchOptionsdictionary中的鍵值,這個(gè)方法是你處理launchOptionsdictionary中的鍵值的最后機(jī)會(huì),那么你就需要在這個(gè)didFinishLaunchingWithOptions方法中對(duì)它們進(jìn)行設(shè)置。

其他不使用這個(gè)app delegate的項(xiàng)目通過觀察didFinishLaunchingNotification的通知也可以獲取到相同的lauchOptions dictionary值,也可以獲取到通知的userInfo字典。這些通知將會(huì)在這個(gè)方法return后實(shí)時(shí)發(fā)出。

2、applicationWillResignActive函數(shù):

applicationWillResignActive函數(shù)??

這個(gè)方法會(huì)在app從活躍狀態(tài)轉(zhuǎn)入非活躍狀態(tài)是被調(diào)用并通知app。這發(fā)生在一些打斷查看程序的情況下(比如一個(gè)來電或者SMS信息),又或者用戶退出了app然后它即將會(huì)轉(zhuǎn)入后臺(tái)運(yùn)行。在后臺(tái)運(yùn)行時(shí),app仍然在持續(xù)工作,但是無法傳送信息。

你需要用這個(gè)方法去暫停運(yùn)行中的人物、禁用計(jì)時(shí)器、并停止OpenGL的幀刷新。游戲需要用這個(gè)method去暫停游戲,一個(gè)app需要在非活躍狀態(tài)下執(zhí)行最小的工作。

如果你的app其他地方?jīng)]有保存用戶數(shù)據(jù),你可以在這里保存并保證它不會(huì)丟失。它在用戶執(zhí)行app時(shí)保存用戶數(shù)據(jù),比如在用戶關(guān)閉一個(gè)數(shù)據(jù)輸入窗口時(shí)保存數(shù)據(jù)。不要把保存app的數(shù)據(jù)放在app進(jìn)行數(shù)據(jù)轉(zhuǎn)換時(shí)。

調(diào)用這個(gè)方法后,app還會(huì)廣播一個(gè)willResignActiveNotification通知來讓需要這些數(shù)據(jù)的項(xiàng)目反應(yīng),以便做好狀態(tài)過渡的準(zhǔn)備。

3、applicationDidEnterBackground函數(shù):

applicationDidEnterBackground函數(shù)??

使用這個(gè)方法來釋放資源空間,廢止計(jì)時(shí)器,然后存儲(chǔ)足夠的app狀態(tài)信息來防止它可能發(fā)生的關(guān)閉行為。你還需要停止app的用戶交互,避免使用共享系統(tǒng)資源(比如用戶數(shù)據(jù)庫(kù))。另外,你必須關(guān)閉OpenGL ES在后臺(tái)中的應(yīng)用。

這個(gè)方法將會(huì)提供5秒鐘的時(shí)間來讓你的app準(zhǔn)備最后的其他任務(wù)和return一些東西。如果你需要額外的時(shí)間來完成最后的一些任務(wù),你可以調(diào)用beginBackgroundTask(expirationHandler:)方法請(qǐng)求額外執(zhí)行時(shí)間。但一般來說,你需要讓方法盡快的返回需要的值,以避免任務(wù)未完成而app關(guān)閉并從內(nèi)存中清除。

你需要在這個(gè)方法完畢前執(zhí)行任何app最前面交互的任務(wù)。而其他的一些任務(wù)(比如保存狀態(tài))等可以被移至?xí)r間列或輔助線程中。比如一些background任務(wù),applicationDidEnterBackground(_:)在結(jié)束前,不需要跑這些任務(wù),你需要請(qǐng)求新增的background額外處理時(shí)間來搞定這些任務(wù)。使用的還是那個(gè)beginBackgroundTask(expirationHandler:)方法。

這個(gè)方法會(huì)在被調(diào)用時(shí)及時(shí)發(fā)出通知,并讓其他程序和功能及時(shí)反應(yīng)并處理任務(wù)。

4、applicationWillEnterForeground函數(shù):

applicationWillEnterForeground函數(shù)

在iOS 4.0以及更高的版本中,這個(gè)方法被用來從background狀態(tài)喚醒a(bǔ)pp轉(zhuǎn)換為活躍狀態(tài)。你可以使用這個(gè)方法撤銷app進(jìn)入后臺(tái)時(shí)的各種限制。這個(gè)方法后面永遠(yuǎn)跟著一個(gè)方法applicationDidBecomeActive(_:),用來讓app從非活躍狀態(tài)進(jìn)入活躍狀態(tài)。

調(diào)用此方法時(shí),會(huì)發(fā)送willEnterForegroundNotification通知。

5、applicationDidBecomeActive函數(shù):

applicationDidBecomeActive函數(shù)??

這個(gè)方法用于app從非活躍狀態(tài)轉(zhuǎn)換至活躍狀態(tài)時(shí),通知app的。這發(fā)生在用戶啟動(dòng)、系統(tǒng)啟動(dòng)或用戶拒接或者關(guān)閉了某些打斷程序比如電話、短信等等。

你可以用這個(gè)方法恢復(fù)當(dāng)app進(jìn)入非活躍狀態(tài)時(shí)的各種限制,比如重計(jì)計(jì)時(shí)器,調(diào)起OpenGL ES幀刷新,如果你的app以前在background狀態(tài)下,你也可以使用這個(gè)方法來刷新用戶交互。

這個(gè)方法會(huì)返回didBecomeActiveNotification通知

6、applicationWillTerminate函數(shù)

這個(gè)方法會(huì)讓在app即將關(guān)閉并從內(nèi)存清空時(shí)調(diào)用,你可以用這個(gè)方法做最后的清除任務(wù),比如釋放共享資源(比如用戶數(shù)據(jù)庫(kù)),保存用戶數(shù)據(jù),使計(jì)時(shí)器無效。這個(gè)方法最多為你提供5秒鐘的處理時(shí)間,時(shí)間完畢后,系統(tǒng)會(huì)清除掉這個(gè)app的所有進(jìn)程。

這個(gè)方法往往不會(huì)被調(diào)用,因?yàn)閍pp往往是進(jìn)入了后臺(tái)運(yùn)行,不過在一些特殊情況下,比如長(zhǎng)時(shí)間后臺(tái)未使用的app還是會(huì)被系統(tǒng)自動(dòng)關(guān)閉,還是可以用這個(gè)方法。方法調(diào)用后,會(huì)發(fā)送willTerminateNotification通知。

這些方法讓應(yīng)用對(duì)象與app委托緊緊相連,在一個(gè)app的狀態(tài)過渡中,比如app啟動(dòng);進(jìn)入后臺(tái)狀態(tài);app關(guān)閉等等——應(yīng)用對(duì)象都會(huì)調(diào)起對(duì)應(yīng)的委托方法,讓你的app去根據(jù)狀態(tài)進(jìn)行處理。你不需要做任何事情來保證這些方法會(huì)在合適的時(shí)間去調(diào)用,app對(duì)象已經(jīng)為你干了這些事兒。

每一個(gè)委托方法都有一個(gè)默認(rèn)運(yùn)行方法,如果你設(shè)置他們的運(yùn)行代碼為空甚至刪除他們,你會(huì)在上述情況發(fā)生時(shí)獲得默認(rèn)運(yùn)行的結(jié)果。當(dāng)然,你也可以加入你自己的代碼到這些方法里來,自定義這些方法執(zhí)行時(shí)的行為。

模版也包含了每個(gè)根方法的示例注解,這些注解描述了這些方法可以為你的app做些什么。你可以參照這個(gè)藍(lán)圖來設(shè)計(jì)很多通用的應(yīng)用層的事件。

在這節(jié)課中,你不會(huì)用到任何自定義的app delegate代碼,所以你不需要對(duì)你的AppDelegate.swift文件進(jìn)行任何修改。

View Controller代碼文件

這個(gè)視窗還有另外一個(gè)資源代碼文件:ViewController.swift。在project navigator中選擇它并打開。

這個(gè)文件定義了一個(gè)UIViewController類的子類,命名為ViewController?,F(xiàn)在這個(gè)類繼承了UIViewController類的所以內(nèi)容。為了實(shí)現(xiàn)你自己的方法,你可以對(duì)UIViewController類中的方法進(jìn)行重寫(override)。

你可以看到在ViewController.swift文件中,模版中對(duì)viewDidLoad()和didReceiveMemoryWarning()方法進(jìn)行了重寫(沒看到didReceiveMemoryWarning()),盡管這些模版中的重新沒有做任何事情,僅僅是調(diào)用了這些在UIViewController 中定義的方法鏡像。你可以加入你自己的代碼去自定義view controller的反饋在這些事件中。

在這個(gè)課程中,你不需要用到didReceiveMemoryWarning() 這個(gè)方法,忽略或者刪除它。然后你的ViewController.swift文件中應(yīng)該像這樣:

你將會(huì)在這個(gè)課程的后面在這個(gè)文件中寫入一些代碼。

Open Your Storyboard

現(xiàn)在你要開始在storyboard上去創(chuàng)建你的app了。storyboard是一個(gè)app用戶交互頁面的展示面板,展示頁面上的內(nèi)容以及頁面之間的交互關(guān)系。你使用storyboard去布局層級(jí)或關(guān)系讓你的app啟動(dòng)起來。當(dāng)你創(chuàng)建了一個(gè)東西你可以馬上看到它,馬上得到反饋哪些在工作哪些沒有,然后可以對(duì)你的用戶交互隨時(shí)進(jìn)行改變。

從上面這個(gè)圖可以看出,你的app中的storyboard僅僅包含一個(gè)視覺頁面,這個(gè)即展示你的app內(nèi)容。視窗左邊的箭頭表示App從這里進(jìn)來,也就是說當(dāng)前這個(gè)視窗是app開始的第一個(gè)視窗。這個(gè)視窗包含了一個(gè)view層以及它的view controller。你將會(huì)很快學(xué)習(xí)到更多關(guān)于view視圖和視圖控制器的知識(shí)。

如果你選擇在iPhone 7的模擬機(jī)上運(yùn)行你的app,視窗中的視圖就是你將在對(duì)應(yīng)硬件設(shè)備上看到的樣子。當(dāng)然,畫布的視窗展示可能與模擬器上的不太一樣,你可以選擇屏幕尺寸和方向在畫布的底部。在這個(gè)例子中,它默認(rèn)是iPhone 7的縱向屏幕,所以看起來畫布和模擬器是一樣的。

盡管畫布展示特定的機(jī)型和設(shè)備朝向,但是創(chuàng)建一個(gè)自適應(yīng)的交互視圖仍然非常重要,自適應(yīng)視圖可以自動(dòng)適應(yīng)任何蘋果設(shè)備和任何朝向。當(dāng)你開發(fā)你的交互頁面時(shí),你可以改變畫布的視窗,可以直觀的感受到在不同尺寸的屏幕中,交互布局是如何改變的。

Build the Basic UI

是時(shí)候來建立一個(gè)基礎(chǔ)的交互界面了。讓我們?yōu)槲覀兊腶pp:FoodTracker添加一個(gè)新美食。

Xcode提供一個(gè)龐大的項(xiàng)目庫(kù),用于在storyboard文件中添加元件和事件。一些是你用戶界面的組成部分,比如按鈕、文本字段。也包括一些試圖控制器和手勢(shì)識(shí)別,用于定義你的app行為,而且不顯示屏幕上。

最常用的組件莫過于view了。Views展示內(nèi)容給用戶,他們是一個(gè)個(gè)塊來組合你的用戶界面,并干凈、優(yōu)雅且有用的展現(xiàn)你的內(nèi)容。Views有一系列的有用的內(nèi)置行為,包括屏幕上的展示和用戶輸入的交互等等。

所有的iOS view組件都是UIView類型,或者是UIView類型的子類。這些UIView的子類往往在展現(xiàn)和行為上更加專業(yè),我們先添加一個(gè)文本字段(UITextField),這是一個(gè)UIView的子類。在你的視窗上,一個(gè)文本框允許用戶輸入一行文本,這個(gè)將會(huì)用來輸入美食的名稱。

你可以輸入command+shift+L來調(diào)起這個(gè)選擇器:

選擇后拖拽出來到canvas上,并為它設(shè)定它的constrain,比如上面離safeArea的top 50個(gè)point,左右各20 point等,當(dāng)然你也可以自己拖拉它到你想要的形狀。

設(shè)置文本輸入框的提示文本

當(dāng)你選擇了文本框組件時(shí),右邊將會(huì)打開對(duì)應(yīng)的屬性檢查器。

屬性檢查器位于第四個(gè)圖標(biāo),它可以讓你設(shè)置你剛才拖拽的組件的屬性。

在屬性檢查器中,找到placeholder這一項(xiàng),輸入meal name

當(dāng)你編輯文本輸入框的屬性時(shí),你還可以設(shè)置系統(tǒng)輸入鍵盤的屬性,比如當(dāng)用戶選擇這個(gè)文本輸入框時(shí),系統(tǒng)鍵盤會(huì)顯示出來。

設(shè)置系統(tǒng)鍵盤

首先你要確認(rèn)在canvas或者頁面層級(jí)樹中,你的目標(biāo)text field是被選中的。

在屬性檢查器中,找到輸入鍵盤的返回鍵然后選擇Done,這將讓你這個(gè)文本輸入框的最下角的返回鍵變成Done。文本改變了。然后你在它的下方勾選Auto-enable Retrun Key,這個(gè)表示用戶只能輸入了文本在文本框中才能點(diǎn)擊Done鍵。防止用戶輸入空。

下一步,我們添加一個(gè)文本在頁面的上部,純文本是無交互屬性的,它只是向用戶展示你設(shè)定的文本內(nèi)容(無交互指的是不能像按鈕那樣有“點(diǎn)擊”等事件)。為了更好的展示組件之間如何聯(lián)系在一起,我們?cè)O(shè)定這個(gè)Label去展示用戶在輸入框中輸入的文本內(nèi)容,這可以很好的測(cè)試輸入框是否獲取到用戶的輸入值并讓它執(zhí)行任務(wù)。

然后我們?cè)偬砑右粋€(gè)button,這個(gè)button可以用來綁定一個(gè)事件,即點(diǎn)擊時(shí),獲取輸入框內(nèi)的文本值,并用這個(gè)文本值修改Label上的值。我們會(huì)獲取到下面這種布局展示。

但是當(dāng)我們?cè)赾anvas的左下角進(jìn)行service和orientation的切換時(shí),比如切換到iPhoneXs,可能按鈕和輸入框顯小,而放在iPhone4里面,輸入框卻顯得很大。這些問題都可以使用Auto Layout來幫助你。Auto layout可以幫助你減少頁面布局的工作量,而由它接管你的布局在各種版本的device和orientation之間的自適應(yīng)問題。

Auto Layout中有一個(gè)非常重要的組件稱之為stack view(UIStackView)。一個(gè)stack view提供橫向或豎向的序列布局。而且它相當(dāng)于一個(gè)小的自動(dòng)布局,根據(jù)它里面的元件大小和位置進(jìn)行自適應(yīng)管理。這讓你會(huì)更好的處理復(fù)雜的布局問題,從而領(lǐng)略到Auto Layout的魅力所在。

你可以像這樣把幾個(gè)組件組合到一個(gè)stack view里面,然后我們?cè)贋檫@個(gè)stack view添加一些限制條件。

我們注意到如果你如果勾選了“Constrain to margins”,這個(gè)會(huì)讓你的scene是位于superview的左右間距位置(margin只對(duì)左右進(jìn)行限制),可以發(fā)現(xiàn)一些空白,而不是頂格展示。top位置要考慮狀態(tài)欄,要注意選擇數(shù)值的參考對(duì)象時(shí),是否為狀態(tài)欄的底部,如果不是,記得要預(yù)留一些空白。

然后我們就能得到這個(gè)界面啦。

Debugging Auto layout

如果你沒有在上述行動(dòng)中取得預(yù)期成果,你可以使用Auto Layout調(diào)試器來幫助你。你可以點(diǎn)擊“刷新布局”和“自動(dòng)布局檢驗(yàn)菜單”時(shí),你也可以在樹狀目錄上方尋找發(fā)現(xiàn)有無紅色或黃色的箭頭,點(diǎn)擊箭頭就可以進(jìn)入到問題界面。

Update frames其實(shí)就是根據(jù)最新的限制條件對(duì)canvas進(jìn)行刷新展示,如果有沖突,會(huì)在canvas中以紅色線標(biāo)識(shí)出來。而Resolve Auto Layout Issues菜單是彈出一個(gè)包含解決辦法的菜單

當(dāng)布局沒有按照我們所期望的去布局,點(diǎn)擊canvas右下角的Resolve Auto Layout Issues按鈕去升起這個(gè)調(diào)試命令菜單。這里面的所有命令都包含兩種形式,一個(gè)影響選擇的view,另一個(gè)影響這個(gè)view controller中包含的所有視圖。如果全部命令為灰色,請(qǐng)重新在樹狀view層中選擇一個(gè)或view controller再重新打開這個(gè)功能菜單。

選擇Reset to Suggested Constraints其實(shí)是讓Xcode按照系統(tǒng)建議的來設(shè)定constraints。而另一個(gè)clear就是這個(gè)選中組件的constraints全清,然后你自己重新添加。

下一課我們要進(jìn)入的是把UI與code聯(lián)系起來。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容