實時顯示iOS編寫UI程式碼效果

發表於2015-05-08

編寫iOS應用UI的方式大概有兩種,一種是Storyboard/Xib,另一種是手寫程式碼。採用Storyboard/Xib方式組織UI,由於提供視覺化的特性,只要從UI庫中拖動UI控制元件,便可以顯示結果,極大地提高開發速度。但面臨一個問題就是多人協作開發,由於所有的UI都放在同一個Storyboard檔案中,使用Git/SVN合併程式碼就會出現衝突。多人協作開發還不是主要問題,有人提出可以建立多個Storyboard來分開UI編寫,而Storyboard/Xib最主要問題是程式碼複用性比較差。所以有些人就選擇手寫UI程式碼,這樣不僅可以解決多人協作開發問題,而且通過自定義控制元件在多個View使用。但每次手寫UI程式碼後都要編譯、構建和執行,最後在模擬器顯示,這樣會拖慢開發速度。如果每次修改UI控制元件後,儲存修改便實時在模擬器顯示修改後結果,就可以極大的提高編寫UI的速度。

Live Change.gif

Auto Layout

Auto Layout是什麼

Auto Layout是一個基於constraint(約束)的佈局系統,它根據UI元素之間約束關係來調整UI元素的位置和大小。

Auto Layout解決什麼問題

  • 更容易適配不同解析度裝置的螢幕(iPhone 6 Plus, iPhone 6, iPhone 5s/5, iPhone 4s/4)
  • 當裝置旋轉時不需要做額外處理
  • 使用constraint來描述佈局邏輯,更利於理解和清晰

如何使用Auto Layout

Auto Layout中約束的類對應是NSLayoutConstraint, 而建立NSLayoutConstraint物件主要有兩種方式,第一種是

上面方法主要意思是,某個view1的attribute1等於(小於或等於/大於或等於)某個view2的attribute2的multiplier倍加上constant。而attribute主要由表示位置(上/下/左/右)和大小(寬/高)的以下幾個值:

簡化一下,使用公式可以表達為:

第二種方式是:

這種方式主要是採用Visual Format Language(視覺化格式語言)來描述約束佈局,雖然語法比較簡潔,但是可讀性比較差和容易出錯。

Auto Layout存在問題

雖然Auto Layout在佈局view方面是非常強大和靈活,但是建立constraint的語法過於繁雜,引用Masonry一個例子:

如此簡單的一個例子都要編寫這麼多行程式碼,想象一下如果建立多個view的constraint時會多麼痛苦啊。另一個方式是採用Visual Format Language (VFL),雖然語法比較簡潔,但是可讀性比較差和容易出錯。

Masonry

為什麼使用Masonry

Masonry是採用鏈式DSL(Domain-specific language)來封裝NSLayoutConstraint,通過這種方式編寫Auto Layout佈局程式碼更加易讀和簡潔。
使用Masonry的MASConstraintMaker來表達相同constraint

甚至可以更短

如何使用

使用Masonry建立constraint來定義佈局的方式有三種:mas_makeConstraintsmas_updateConstraintsmas_remakeConstraints

1. mas_makeConstraints

使用mas_makeConstraints建立constraint後,你可以使用區域性變數或屬性來儲存以便下次引用它;如果建立多個constraints,你可以採用陣列來儲存它們。

2. mas_updateConstraints

有時你需要更新constraint(例如,動畫和除錯)而不是建立固定constraint,可以使用mas_updateConstraints方法

3. mas_remakeConstraints

mas_remakeConstraintsmas_updateConstraints比較相似,都是更新constraint。不過,mas_remakeConstraints是刪除之前constraint,然後再新增新的constraint(適用於移動動畫);而mas_updateConstraints只是更新constraint的值。

想了解以上三個程式碼片段的更多細節,可以下載Masonry iOS Examples工程查閱。

Classy

Classy簡介和特性

Classy是一個能與UIKit無縫結合stylesheet(樣式)系統。它借鑑CSS的思想,但引入新的語法和命名規則。

靈活內嵌的語法

{ } : ; 這些語法符號是可選的,你可以選擇適合自己的風格來表達stylesheet。

你可以使用{ } : ; 來限定stylesheet

或者你使用空格來限定stylesheet

預設樣式

Classy在應用程式Bundle預設查詢檔名為stylesheet.cas的樣式檔案。如果你採用這個檔名,你可以不用做任何東西就能載入樣式檔案。
但如果你想指定其他file path(樣式檔名),你可以建立[CASStyler defaultStyler]

如果你還想當發生錯誤時,獲取錯誤資訊以便於除錯,可以使用-(void)setFilePath:error:

如果你是使用Storyboard/Xib組織UI介面,那就需要在main.mint main(int argc, char * argv[])方法設定 filePath,這樣可以確保在建立UIWindow之前載入stylesheet。否則(採用手寫UI程式碼),你在 AppDelegate.m- (BOOL)application:didFinishLaunchingWithOptions:方法設定filePath

Live Reload

Live Reload是實時顯示編寫UI程式碼效果的關鍵特性,它能夠實時檢查stylesheet檔案變化,無需重新編譯、構建和執行模擬器,從而極大提高開發速度。
為了啟用Live Reload,你需要指定stylesheet路徑,並且只執行在模擬器上。

Selectors

Style Selectors是指定哪個view使用哪種樣式的方式。主要有三種方法來指定目標view:

  1. Object Class
  2. View Hierarchy
  3. Style Class

你可以混合使用三種方法,例子如下:

想了解具體如何使用,請查閱官網Selectors章節

為了避免與Objective-C的message selectors混淆,術語style selectors表示Classy stylesheets的selectors

Properties

Classy支援所有UIAppearance的屬性和方法,也支援與UIAppearance無關的很多屬性。Classy使用與UIKit相同屬性命名,所以你不必考慮如何將style property對映到Objective-C的property
UIPageControl類的屬性如下:

style property的名字採用與objective-c一樣的名字

style property的命名規則採用kebab case

想了解具體如何使用,請查閱官網Properties章節

Keep it DRY(Don’t Repeat Yourself)

在程式設計中一個很重要的原則就是避免重複,這不僅可以大量減少重複程式碼,並且使得程式碼更加容易複用和維護。Classy提供三種方式避免程式碼重複:grouping,nestingvariables

Grouping

如果有兩個以上的style selectors共用相同的屬性時

我們可以提取相同的屬性到分組style selector中

Nesting

如果兩個以上style selectors共用相同的view hierarchy時

我們通過nesting方式將view hierarchies表達成這樣方式

Variables

Classy讓你通過定義variables來將多個相同的style property值儲存以便共享。Variable命名規則如下:

  • 必須以大小寫字母$符號開頭
  • 可以包含_-或任何字母數字

    最後官方還提供一個例項來解釋具體如何使用:Custom Views Example

ClassyLiveLayout

ClassyLiveLayout通過結合Classy stylesheets與Masonry一起使用,能夠在執行的模擬器中微調Auto Layout約束實時顯示效果的工具。

ClassyLiveLayout一個核心category:UIView+ClassyLayoutProperties,在UIView定義以下屬性:

cas_margincas_size分別表示UI元素的位置和大小,而其餘的屬性都是對兩個屬性進一步細分。我們可以從stylesheets中訪問style properties來定義constraints佈局,做到將資料與程式碼分離,有利於修改和複用程式碼。

我們可以在updateConstraintsupdateViewConstrains定義佈局時引用style properties

當定義view layouts時,將Auto Layout的constraints都放在stylesheets中實時載入(Live reload)。如果你修改constraints,無需重新編譯、構建和執行模擬器便能實時看到修改後的效果。

示例工程

配置工程

由於需要引用Masonry,Classy和ClassyLiveLayout,Podfile配置如下:

編寫程式碼

1. 新增stylesheet.cas檔案到工程

當安裝好Masonry,Classy和ClassyLiveLayout後,第一次執行專案會出現沒有stylesheet.cas檔案錯誤:


No stylesheet.cas file error.png

只要向工程新增空的stylesheet.cas檔案即可。


Create stylesheet.cas file.png

2. 建立LiveView類,該類繼承SHPAbstractView


Create LiveView inherit SHPAbstractView.png

ViewController建立LiveView物件,然後被self.view引用。


Setup root view in ViewController.png

當編譯執行時,在SHPAbstractView.h由於找不到UIView出現編譯錯誤。


SHPAbstractView Compile error.png

只需引入UIKit便可以解決,但執行一下應用程式,出現一下錯誤:


Must override methods.png

主要原因是任何自定義UIView繼承SHPAbstractView都需要override兩個方法:- (void)addSubviews- (void)defineLayout,我們可以檢視SHPAbstractView的原始碼可知:


SHPAbstractView Source Code .png

所以只要在LiveView.m檔案覆蓋兩個方法即可

3. LiveView類設計

LiveView主要由包含redBoxViewblueBoxView兩個屬性,redBoxView表示紅色方塊,blueBoxView表示藍色方塊。

4. LiveView類實現

由於SHPAbstractView類如何初始化View已經做了處理,暴露兩個介面- (void)addSubviews-(void)defineLayout分別處理構建view hierarchy和定義佈局,子類只要覆蓋SHPAbstractView這兩個方法就可以建立LiveView了。
但是我們將Auto Layout的constraints都放在stylesheets中實時載入(Live reload),即放在本工程的stylesheet.cas檔案,將佈局資料和佈局程式碼分離。

有了constraints資料後,便可以在程式碼佈局:

5. 模擬器支援Live Reload

為了啟用Live Reload,你需要指定stylesheet路徑,並且只執行在模擬器上。


Support Live Reload.png

此時效果:


Live Change.gif

6. 分離樣式檔案

由於有網友提出這樣一個問題:如果所有view的樣式都放在同一個stylesheet.cas檔案,會讓stylesheet.cas檔案繁雜,並且當多個人協同開發時,不易於合併程式碼,所以有必要將樣式檔案分離到多個檔案中。

1.建立variable.cas檔案,並將redBox對應UIView的樣式放在variable.cas檔案中。


variable.cas file.png

2.在stylesheet.cas樣式檔案使用@import指令引用variable.cas檔案


stylesheet.cas file.png

最後效果


Live Change 1.gif


Live Change 2.gif

示例程式碼存放地址:LiveAutoLayout

總結

之前手寫UI程式碼每次更改一般都要重新編譯、構建和執行模擬器才能看到效果,但結合使用Masonry,Classy和ClassLiveLayout之後,告別這個費時過程,極大地提高開發速度;不僅如此,我們將Auto Layout的constraints都放在stylesheets中實時載入(Live reload),將佈局資料和佈局程式碼分離,使得程式碼更加複用和維護。Classy還提供三種避免重複方法:Grouping, Nestting和Variable,儘可能複用樣式資料。
這是本人第一次編寫技術部落格,可能有很多錯誤和漏洞,希望大家多多指點,也希望這篇文章能夠幫助到大家。

擴充套件閱讀

相關文章