2019獨角獸企業重金招聘Python工程師標準>>>
什么是多狀態 Layout
對于大多數 App 而言,項目中都有多狀態加載 View 這種需求,如下圖所示。
對應到開發中,我們通常會開發一個對應的自定義 layout 用于根據頁面不同的狀態來顯示不同的提示 view。
在項目中,我們大多會在開發初期就把這套 layout 框架寫好,然后其他人的自己的開發過程中直接使用即可。如下所示:
<name.gudong.MJMultipleStatusLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"><ListViewandroid:id="@+id/lv_activity_center"android:layout_width="match_parent"android:layout_height="match_parent" /></name.gudong.MJMultipleStatusLayout>
這篇文章不討論如何去實現這樣的自定義 loading layout,Github 上這樣的 layout?太多了,這里主要思考、總結在實際開發中開發這樣的自定義 Layout 時應該注意那些地方。
但是為了說明方便,這里還是采用的方案簡單敘述一下。
為了后文描述方便,這里把這個多狀態自定義 Layout 先稱為 MultipleStatusLayout。
實現方案
在實現 MultipleStatusLayout 時,首先選擇繼承一個 ViewGroup 作為自己的父類,然后默認把內部的第一個子 View 作為 ContentView,其它各種情形下對應要顯示的 layout view,根據不同的加載狀態,在 MultipleStatusLayout 中通過動態 addView 去控制對應 layout 的加載顯示,也可以通過 ViewStub 把不同情形的 layout 進行懶加載,然后對外提供不同的方法,方便外部調用、控制不同狀態下的 layout 顯示。
嗯,簡單說來就是這樣,原理很簡單,實現起來也沒什么技術難度,對于一般的開發人員只要一開始明白具體的產品邏輯和實現思路,相信花不了多少時間就可以完成這樣的 MultipleStatusLayout。具體這種方式的實現可以參看一個開源項目?的實現。
下面著重列舉一下開發 MultipleStatusLayout 過程中的注意點或者要點。
Tips
考慮到 MultipleStatusLayout 開發完成后,會在項目中的很多頁面中應用,而且很多時候是作為頁面頂級父容器而存在,所以開發過程中一定要注意其性能還有穩定性,否則一旦出現問題,整個項目中應用到該 MultipleStatusLayout 的頁面都會隨之出現問題。
以下就從性能角度、可維護性、穩定性等方面考慮出發,列舉一些開發 tip 。
選擇最合理的父容器
首先 FrameLayout、RelativeLayout、LinearLayout 都可以作為 MultipleStatusLayout 的父類,拋開現在的應用場景不談,都知道 RelativeLayout 在 layout 時需要 measure 兩次,所以對于一個未來要在很多頁面中使用的 Layout ,把 RelativeLayout 作為父類這個方案首先 pass 掉。
但是因為 MultipleStatusLayout 中顯示的 view 大都需要居中顯示,所以使用 RelativeLayout 相對比較容易控制居中位置,這可能是很多人選擇 RelativeLayout 作為父類的初衷。這里自己可以做一下權衡。
關于 LinearLayout 和 FrameLayout,如果按照上一節提到的實現方案,其實都可以采用,不過考慮到該類 Layout 的應用場景,建議選擇 FrameLayout。
因為MultipleStatusLayout 未來在大多數情況下是作為頁面父容器存在的,既然是父容器,內容可能會有各種變化,這時使用 LinearLayout 這種線性布局就會在布局時顯得特別局限,比如一些頁面可能需要在 MultipleStatusLayout 之上顯示一個 FloatActionButton 或者其他的 view,這時使用 FrameLayout 就會好做很多也會靈活很多。
選擇最優的加載 View 方式
如何控制這些多狀態對應的 View ? 對于一般的情形,至少有兩種 View 類型,一種是加載中的 loading 樣式 view,一種是異常狀態的 layout view,當然還可能有更多具體的情形。
不同的樣式對應一個不同的布局,為了簡便我們可以一次性的把所有狀態對應的布局都寫在一個 layout 布局里,然后可以通過控制隱藏、顯示來根據不同的狀態來展示不同 view,這是最直接的想法。
但是,只要多思考一步,就會發現這種方式非常不可取。因為很多時候,MultipleStatusLayout 作為一個父容器只關心自己的 ContentView,異常頁面和加載頁面甚至可能沒有機會出現,但是現在這樣做就表示,這個頁面不論有沒有異常或者加載邏輯,你的布局里都會存在對應的 layout 布局代碼。這樣在界面繪制時就會白白耗掉多余的時間。
而且這個 Layout 后續會在項目很多頁面用到,所以這里的布局耗時問題放大后就顯得很嚴重。
鑒于此,取而代之的更好的做法應該是動態去 addView,只有這個頁面第一次調用 loading 或者 showError 這樣的方法,我才去把對應布局加載進來,當然這里使用 ViewStub 也是一樣的效果。
這里也就是說,只有調用了相應的方法,才去加載對應的 layout.
資源命名
其實這個問題是自己開發公用 Api 普遍面臨的問題,由于開發 MultipleStatusLayout 可能會定義一些顏色資源或者背景資源,這里建議所有資源開頭使用一個固定的開頭,這樣可以防止跟主版本中的資源重名。進而早成一些奇怪的 UI 問題或者編譯問題。比如按鈕的背景你可以定義為 msl_btn_normal 而不是 btn_normal,文字的顏色你可以定義為 msl_text_white 而不是 text_white。這樣就可以有效避免一些資源沖突。
更多關于如何開發一個第三方庫,可以查看天之界線的開發第三方庫最佳實踐
提供友好的方法調用方式
既然是提供給大家使用,你就應該在方法命名上多花點心思,最好見名之意,這樣大家調用時也會舒服很多。
另外對外提供 Api 時也應該保持克制。不要一下子提供出去太多的方法,不論有用沒用,一下子都對外提供,這樣會對后續的維護造成隱形的負擔,因為提供的公用方法越多,表示你后續都要對這些方法進行維護。
最好的原則就是用到什么提供什么,不要提前設計。
另外,隨著項目迭代,對外提供方法的參數可能會變得多起來,比如以前顯示錯誤頁面的方法是
void showErrorView(Stirng error)
后來要增加自定義的 icon 或者點擊事件響應,這時你就需要擴展方法參數,往往這種參數可能會變得很多不可收拾,這時建議使用 Build 構建模式設計,如下示例所示:
showErrorView(StatusViewConfig config)
調用時就可以這樣調用
showErrorView(new StatusViewConfig.StatusViewBuild(getContext()).icon(icon).message(message).subMessage(subMessage).layoutMode(mLayoutMode).withActionText(actionText, clickListener).build())
良好的文檔
當你開發完成后,最好趁熱寫一份簡單明了的使用文檔出來,這樣大家就可以直接對照文檔使用你寫的庫,不用去關心代碼實現,直接調用 Api 就可以完成自己的業務需求,同時也省的自己去面對面跟別人講怎么使用了。
前段時間在 V 站上看到一個問題,說你們公司使用什么樣的文檔管理工具?其中有一個回答言簡意賅,很有意思,四個字?口口相傳
。
其實對于任何一個項目都是,有時間寫點文檔,梳理自己思路的同時方便別人,何樂而不為。
其他
這種 Layout 在項目中會隨著項目的更新迭代而不斷的更新,所以一開始你就應該知道,后續還要不斷迭代更新,所以代碼設計實現時應該留意擴展性。
另外,相關的開源方案有很多,建議一開始可以參考一些好的方案,然后結合自己項目的實際需求,來開發維護屬于自己項目的一套框架。因為多狀態 loading 加載提示框架大都和產品設計強相關,不具備一般的通用性。
下面列舉一些自己收集到的多狀態加載開源方案,方便對比。
開源方案
StatefulLayout
progress-activity
StateLayout
MultipleStatusView
總結
同樣功能的 Layout 可能在不同的業務場景下實現方式也會有很大的區別,所以不論哪種實現方式,無所謂好壞,只要適合就好。但是開發此類 Layout 要遵循的基本準則、以及要注意的點應該大都相同,希望此文可以給你一些啟示幫助。