製作一個類似蘋果VFL的格式化語言來描述UIStackView

發表於2016-07-22

在專案中總是希望頁面上各處的文字,顏色,字型大小甚至各個檢視控制元件佈局都能夠在發版之後能夠修改以彌補一些前期考慮不周,或者根據統計資料能夠隨時進行調整,當然是各個版本都能夠統一變化。看到這樣的要求後,第一反應是這樣的頁面只能改成H5,或者嘗試使用React Native來應對這種要求。

既然UIStackView已經提供了一種既先進又簡潔的佈局思路,為何不通過製作一個類似VFL這樣的DSL語言來處理佈局。這樣不就能夠通過下發一串DSL字串的方式來進行內容樣式甚至佈局的更換,不用跟版,還能使多版本統一。同時在端內直接用這樣的DSL語言來寫介面不光能夠減少程式碼量易於維護,還能夠很直觀方便的看出整個介面佈局結構。

AssembleView(組裝檢視)和PartView(零件檢視)

在設計格式化語言之前需要對佈局做個統一思想進行管理,在看了WWDC裡關於UIStackView的介紹後感覺任何複雜的佈局都能夠通過這樣一種組合排布再組合排布的思路特別適合用格式化語言來描述。於是我想出兩個檢視概念。

一個是AssembleView組合檢視,專門用於對其PartView子檢視進行排列,比如說是水平排列還是垂直排列,PartView是按照居中對齊還是居左等對齊方式,各個PartView之間間隔是多少。

PartView決定自己檢視型別,內容,無固定大小的可以設定大小,同時AssembleView可以作為PartView被加入另一個AssembleView裡進行排列,這樣各種設計圖都可以在初期通過拆解分成不同的AssembleView和PartView進行組合套組合佈局出來。

格式化語言

接下來是如何通過格式化語言來描述AssembleView和PartView。“{}”符號裡包含的是AssembleView的設定,“[]”符號裡是PartView的設定,“()”裡是他們的屬性設定,“”可以將物件帶入到設定裡。下面舉幾個例子說明下。完整Demo放到了Github上:https://github.com/ming1016/STMAssembleView

三個星星水平對齊居中排列

h表示水平排列horizontal,c表示居中center,“[]”PartView會根據順序依次新增排列,imageName屬效能夠指定本地圖片

11center
三個星星水平對齊居中排列

AssembleView裡套作為PartView的AssembleView的複雜情況

color可以指定文字顏色,font指定文字大小

12mid
AssembleView裡套作為PartView的AssembleView的複雜情況

給PartView設定背景色和按鈕

設定背景色使用backColor,背景距離設定的PartView的內容間距通過backPaddingHorizontal屬性設定水平間距,backPaddingVertical設定垂直間距,“”符號帶入的button通過button屬性設定。

13followBt
給PartView設定背景色和按鈕

AssembleView設定忽略約束的方法

水平排列時,通過ignoreAlignment屬性設定忽略left約束,如果是垂直排列設定top忽略。

14des
AssembleView設定忽略約束的方法

將前面的檢視組合成一個AssembleView

15as
將前面的檢視組合成一個AssembleView

AssembleView的屬性

  • 當在“{}”裡面第一個字母是v表示垂直排列vertical,是h表示水平排列horizontal
  • 第二個字母是c表示所有PartView居中對齊center,l表示居左對齊left,r表示居右對齊right,t表示居上對齊top,b表示居下對齊bottom。
  • padding:預設各個PartView的間距。

PartView的屬性

如果不希望通過屬性生成檢視,可以通過在[後直接填入帶入物件對應的key,然後再在()裡設定屬性。

PartView佈局相關屬性

  • width:UILabel和UIImage這樣有固定大小的可以不用設定,會按照固定大小的來。
  • height:有固定大小的可以不用設定。
  • isFill:垂直排列時會將寬設定為父AssembleView的寬,水平排列時會將高設定為父AssembleView的高。
  • padding:設定後會忽略父AssembleView裡設定的padding,達到自定義間距的效果。
  • partAlignment:可以自定義對齊方向,設定後會忽略父AssembleView裡設定的對齊。值可填center,left,right,top,bottom。
  • ignoreAlignment:設定忽略的約束方向,在父AssembleView不需要由子PartView決定大小的情況下,可以通過打斷某個方向約束來實現拆開排列的效果。值可填center,left,right,top,bottom。

PartView權重相關屬性

  • crp:Compression Resistance Priority的設定,根據權重由低到高值可以設定為fit,low,high,required。對應的UILayoutPriority的分別是UILayoutPriorityFittingSizeLevel,UILayoutPriorityDefaultLow,UILayoutPriorityDefaultHigh,UILayoutPriorityRequired。
  • minWidth:對應NSLayoutRelationGreaterThanOrEqual,設定一個最小的寬
  • maxWidth:對應NSLayoutRelationLessThanOrEqual,設定一個最大的寬

PartView檢視控制元件相關設定

通過以下屬性即可生成對應的UILabel,UIImageView或者UIButton等控制元件檢視,而不用特別指出需要生成哪種控制元件檢視

  • text:設定文字內容
  • font:設定字型,可以帶入一個UIFont,也可以直接設定一個字型大小,解析時會判斷型別。
  • color:設定顏色,可以帶入一個UIColor,也可以直接設定一個十六進位制顏色,解析時會判斷型別。
  • imageName:設定本地圖片,值是本地圖片名稱。
  • image:帶入一個UIImage。
  • imageUrl:設定一個網路圖片的url地址,ps:目前需要通過來帶入一個字串。

PartView的通用設定

可以為PartView建立一個底部檢視,並設定其樣式。也可以新增一個UIButton設定UIControlStateHighlighted時的樣式。

  • backColor:設定底部檢視的顏色,可以帶入一個UIColor,也可以直接設定一個十六進位制顏色,解析時會判斷型別。
  • backPaddingHorizontal:設定當前PartView檢視距離底部檢視top和bottom的間距。
  • backPaddingVertical:設定當前PartView檢視距離底部檢視left和right的間距。
  • backBorderColor:設定底部檢視邊框的顏色,可以帶入一個UIColor,也可以直接設定一個十六進位制顏色,解析時會判斷型別。
  • backBorderWidth:設定底部檢視邊框寬。
  • radius:設定底部檢視的圓角半徑。
  • button:帶入一個button。
  • buttonHighlightColor:設定button在UIControlStateHighlighted時的顏色,預設是透明度0.05的黑色。

解析格式化語言

解析過程的第一步採用掃描scanner程式將字串按照分析符號表將字元流序列收集到有意義的單元中。

第二步將這些單元逐個歸類到對應的類別中。比如解析到“()”裡內容時就將其歸類到對應的AssembleView的屬性或者PartView的屬性類別中。在歸類過程中會出現PartView是AssembleView,這個Assemble裡面又有這樣作為PartView的AssembleView這樣層層套的情況,所以需要採用類似引用計數方式保證在最後一個“}”符號結束時能將整個Assemble遞迴進行解析。

第三步將各個類別集合轉換成對應原生程式碼從而生成對應的檢視佈局。

具體實現可以檢視STMAssembleView.m檔案。Github地址:https://github.com/ming1016/STMAssembleView

如何生成頁面

生成頁面需要實現格式化語言對應的原生程式碼,所有PartView的屬性都會存放在STMPartMaker裡,包括帶入的自定義檢視還有用於生成檢視控制元件的屬性等。PartView屬性設定完成後會在STMPartView這個類中先決定對應的檢視控制元件,並將STMPartMaker裡的屬性都設定上。實現程式碼可以檢視STMPartView.m裡的- (STMPartView *)buildPartView方法。

接下來STMAssembleView會在buildAssembleView時進行佈局,具體實現程式碼可以檢視STMAssembleView.m裡的- (STMAssembleView *)buildAssembleView方法。

相關文章