布局編碼的未來
客戶端布局是客戶端開發最為基礎也是最為重要的編程實踐之一,對於一個有著良好技術架構的客戶端開發團隊來說,布局編碼工作占業務開發工作量的80%。顯然,對於布局編碼進行深入的思考、總結統一最佳實踐、提供有力的基礎架構支撐,對於提升客戶端開發團隊的生產力非常關鍵。
同時,客戶端動態化是當前移動開發領域的技術熱點,也是移動開發未來最為重要的發展方向之一。當前業界湧現出了React Native和Weex等解決方案,但是這裡就存在迷一樣的事實:所有框架的指導思想都是保持Web基本布局實踐的前提下,通過原生渲染來提高性能。但是,在移動互聯網時代,開發者應該擴展一下問題解決思路:Web及其Web的布局實踐不是唯一的道路,甚至不可能是最好的思路。
本文從點評App iOS團隊的布局實踐——匠心布局開始說起,向大家展示一種反常規甚至反直覺的布局方案,和點評移動團隊按照匠心布局全新設計的跨平台動態化布局框架畢加索(picasso)。
匠心布局
匠心布局原本是點評iOS布局邏輯開發最佳實踐的總結,隨著跨平台動態化布局框架畢加索(picasso)的推出,使匠心布局成為跨平台的標準實踐。
布局邏輯的本質
在對比布局方案和思路之前,我們先思考一下布局需求的本質是什麼?
布局的本質就是:
1. 指定視圖的大小和位置n2. 響應變化,在產生變化的時候重新指定大小和位置n
變化的來源
我們可以將變化的來源劃分為兩個方面,內部來源和外部來源:
1. 內部來源n 內容變化n 國際化n 動態字體nn2. 外部來源n 多屏幕適配n 來電錄音提示條n 設備旋轉n
說起適配,可能大家首先想到的就是針對屏幕的適配,實際上內部變化來源中的內容變化一直都是布局編碼的核心需求,布局總會涉及到諸如:根據文本長度調整布局,根據具體業務特點排布icon等需求。
外部來源總結下來就是對視圖容器變化的適配,這裡其實並不能簡單的等同於對機型解析度的適配、設備旋轉、來電錄音提示條、分屏設計等因素的組合效應。
簡單回顧下iOS布局需求發展歷史(圖片來自WWDC):
曾經有那麼一段時間,iOS開發者的世界還是簡單而美好的:)點評iOS 最佳布局實踐
點評iOS的布局實踐總結起來非常簡單的,其中核心的特點是:
1. 純代碼布局n2. no autolayoutn
其中純代碼布局指的是全完使用Objective-C完成布局邏輯,不使用Interface Builder,也不使用Interface Builder(IB)衍生出來的autolayout,以及任何基於autolayout的DSL實現。
事實上這並不是一個全新的思路,我們在蘋果方案的文檔中找到這樣一段話:
1. programmatically defining a view』s frame provides the most flexibility and power.n2. When a change occurs, you can literally make any change you want.n
顯然蘋果方案也認為純代碼布局有著靈活性巨大優勢,但是他們並沒有想清楚具體的布局編碼實踐,然而點評的匠心布局憑藉「錨點」的概念完美的解決了布局代碼難以編寫,難以維護的問題。在這樣的前提之下,Auto Layout之類聲明式方案沒有任何優勢,卻因為核心引擎實現的複雜度帶來穩定性和性能方案的重重問題。
錨點的力量
邏輯表達的困境
使用具備完整編程語言表達能力的布局,顯然在靈活性和性能方面具備壓倒性的優勢。但是,無論Android還是iOS平台上,原生API寫出的布局代碼都顯得非常拙劣,難以編寫和理解,進而變得難以維護。
例如就控制項居中的需求來講,iOS的原始方案可能是這樣:CGRect frame = view.frame;nframe.origin.x = bgView.frame.size.width / 2 - view.frame.size.width / 2;nframe.origin.y = bgView.frame.size.height / 2 - view.frame.size.height / 2;nview.frame = frame;n
可能是這樣的:
view.frame = CGRectMake(bgView.frame.size.width / 2 - view.frame.size.width / 2,n bgView.frame.size.height / 2 - view.frame.size.height / 2,n view.frame.size.width,n view.frame.size.height);n
也可能是這樣的:
view.center = CGPointMake(bgView.frame.size.width / 2 - view.frame.size.width / 2,n bgView.frame.size.height / 2 - view.frame.size.height / 2);n
然而這樣的布局邏輯代碼顯然是不可維護的,由此產生的「純代碼布局是腦殘行為」的論斷也是可以理解的。蘋果和谷歌官方給出的方案就是Auto Layout、LinearLayout等「聲明式」布局邏輯,而應對客戶端動態化的方案,人們自然而然會想到Web的HTML+CSS,以及CSS的超頻版本Flexbox和Gridlayout等等。
錨點及其應用
純代碼布局在表達上所遇到的困境本質是,系統原生介面暴露的view.origin.x, view.origin.y, 與開發過程中所表達的諸如「居中對齊」, 「左對齊」, 「底對齊」等需求描述語義存在這小小的距離。而通過對視圖增加錨點概念:
1. leftn2. rightn3. topn4. botomn5. centerXn6. centerYn
7. widthn8. heightn
則消滅了需求和本質實現的語義差距,於是居中邏輯表述變成了:
view.centerX = bgView.width / 2nview.centerY = bgView.height / 2n
類似的「左對齊」:
view2.left = view1.leftn
「底對齊」:
view2.bottom = view1.bottomn
這樣一來,布局需求的描述和布局實現如出一轍,容易編寫,容易維護。錨點的概念讓代碼布局邏輯簡潔清晰,使純代碼布局成為可能甚至成為優選方案。
開發效率
我們認為,對於關鍵技術和框架的選擇,開發效率的考慮尤為重要。總結下來,下面兩點非常關鍵:
1. 即時反饋的編程環境n2. 簡潔強力的語義表達n
即時反饋的編程環境
IB & Playground
Live Reload
- IntelliSense
我們看到這些編程環境的特點:
1. 即時看到執行結果n2. 即時看到執行過程(中間步驟結果)n3. 即時的反饋可用介面n
實際上前端開發同學之所以能在一個拙劣混亂的基礎架構上達成較高的開發效率,很大程度上收益於前端開發很容易搭建一個即時反饋的編碼環境,尤其是Live Reload支持,對生產力提升尤為明顯,甚至彌補了語言和良好IDE支持的缺陷。這其中動態的能力是關鍵,但並不代表Web是客戶端動態化唯一的方案。綜合利弊,我們可以吸取三端編程實踐最好的東西,構建最富有生產力的客戶端動態化框架。譬如,picasso利用JavaScript的動態特性, 實現了Live Reload,又藉助TypeScript+Visual Studio Code+Babel達到了傳統客戶端靜態類型語言的開發體驗,提高生產率的同時,還從工程上保證了可靠性。
簡潔強力的語義表達
我們這裡使用一個簡單的例子,關於水平方向上約束的表達對比。
首先我們看到,官方使用偽代碼的形式示意說明約束表達的含義,顯然偽代碼肯定是廣大人民群眾喜聞樂見的形式:
RedView.Leading = 1.0 x BlueView.trailling + 8n
然後就面臨這血淋淋的現實,模式的約束構造方式是這樣的:
[NSLayoutConstraint constraintWithItem:blueViewn attribute:NSLayoutAttributeTrailingn relatedBy:NSLayoutRelationEqualn toItem:redViewn attribute:NSLayoutAttributeLeadingn multiplier:1n constant:8];n
很顯然,沒人原意去寫這樣的代碼,於是GitHub上湧現了大量的基於autolayout的DSL,選一個其中的翹楚:Catography(Swift)來說明,寫出來的代碼是這樣的:
layout(blueView, redView) { blueView, redView inn redView.leading == blueView.trailing + 8n}n
如果能選擇性的忽略layout函數調用,block體裡面的約束表達已經和偽代碼描述如出一轍了,最後我們看下匠心布局的寫法是什麼?
redView.left = blueView.right + 8n
對比下來匠心布局的表達是秒殺對手的,實際上匠心布局只做了最簡單的一層抽象,毫無疑問是穩定性和執行效率更高的方案。
配合屈指可數的數個錨點,匠心布局代碼無異於表達布局需求的偽代碼,這樣的代碼具有最高的可維護性,顯然對提高生產力有著巨大的好處。picasso
picasso(畢加索)picasso是我們基於上述的匠心布局理念開發出的跨平台動態化布局框架。它有如下幾個優點:- 配合100%的單元測試,picasso核心引擎穩定性值得信賴; picasso提供開放而統一的擴展體系,對控制項的擴展支持只需要實現一個簡單的wrapper,甚至絲毫不侵入自定義控制項的實現。
簡單描述一下picasso框架的基本原理。picasso接受使用匠心布局實現布局編碼邏輯的js文件和和業務數據,在JSCore中執行JavaScript邏輯,並輸出頁面視圖樹的中間表示PicassoModel,而後由picasso引擎構建出不同平台的視圖樹。其中picasso計算的過程可以在手機後台線程完成,並且picasso在進行視圖樹構建的時候可以做極致的性能優化,可以認為picasso實現的視圖可以有比原生代碼實現更好的流暢度。
除了picasso核心引擎,picasso也是客戶端動態布局一整套最佳實踐總結。picasso-server提供了完整的Live Reload編程體驗,推薦使用的VSCode+TypeScript+Babel的組合,帶來的是客戶端原生編程的安全性和便利性;同時,picasso-server還提供了項目和單文件的腳手架功能;隨著picasso布局的深入使用,picasso將匯總廣泛豐富的最佳實踐,更進一步的促進生產力的提升。
顯然熱部署能力是現階段各個業務對於picasso的「剛需」,即使放棄使用picasso的熱部署能力,picasso解決方案所提供的Live Reload、跨平台、簡潔強力的布局DSL,都能大大提升開發效率。
預測未來最好的方式就是創造未來,畢加索(picasso)就是我們創造出的布局編碼的未來。作者簡介
大為,美團點評公司點評平台iOS負責人,資深布局師,主導研發包括piccaso在內的一系列基礎框架和基礎設施,有效支撐了美團點評移動業務的蓬勃發展。
點評平台移動技術團隊,同時肩負了平台性業務研發和基礎框架的研發工作,在支撐美團點評業務高速發展的同時,積澱了一系列的基礎框架、研發技術流程等方面的最佳實踐,未來期待和業界有更多交流。
不想錯過技術博客更新?想給文章評論、和作者互動?第一時間獲取技術沙龍信息?
請關注我們的官方微信公眾號「美團點評技術團隊」。
推薦閱讀:
※Windows CE簡史(一)
※從目前的情況看,準備好做 Windows phone 7 應用開發有前途嗎?為什麼?
※【Android源碼研讀】FragmentManager與FragmentTransaction
※Windows 界面開發的歷程