蛋疼:UI布局重構(gòu)的幾個(gè)思考

這篇作為XDroid UI系列的最后一篇,我想談?wù)勗赨I布局重構(gòu)時(shí)的幾個(gè)思考和取舍。

四個(gè)月前,接手公司項(xiàng)目,隨即進(jìn)行了一系列的重構(gòu),主要陣對底層庫如UI、Cache、Event、Net等。

對于UI,我們一定會(huì)面對一個(gè)事實(shí):任何一個(gè)設(shè)計(jì)Api通信的界面,都會(huì)包含Loading、ErrorEmpty、Content四個(gè)狀態(tài)。
因此,我們有必要封裝一個(gè)ViewGroup,來更方便的實(shí)現(xiàn)需求。

取一個(gè)什么名字?

根據(jù)其實(shí)現(xiàn)的效果,取名為ContentLayout。

藍(lán)圖:我們可以如何使用?

這其實(shí)屬于需求方面的內(nèi)容了,先意淫一下吧。實(shí)現(xiàn)最終我們想這樣:

  • 靈活,不受場地(布局層次)的限制,不受控件大小的限制
  • 簡單:不需要寫很多重復(fù)代碼,api使用流暢
  • 容易定制

思路:怎么實(shí)現(xiàn)上述需求?

我一開始有兩個(gè)思路:

  • 在基類中,創(chuàng)建一個(gè)ContentLayout,將整個(gè)Activity & FrameLayout 的布局設(shè)置成其子布局,ContentLayout中提供對應(yīng)的api。
  • 將ContentLayout作為自定義ViewGroup,提供自定義attr設(shè)置

我們對兩種思路進(jìn)行分析:
第一種思路其實(shí)也可實(shí)現(xiàn),但是它有很多限制:

  • ContentLayout作為了Activity & Fragment 的實(shí)際rootView,其大小一般都:match_parent,其大小和布局層級會(huì)受到很大的限制。
  • 只能通過代碼設(shè)置loading、error、empty對應(yīng)的布局
  • 侵入性太強(qiáng),特別針對content對應(yīng)的布局文件

第二種思路,則可以完美實(shí)現(xiàn)前面的需求:

  • ContentLayout作為一個(gè)ViewGroup,可以用在任何地方任何層級,適合界面的某部分需要loading的需求
  • 其自定義attr可以方便的在布局文件中就指定對應(yīng)狀態(tài)的布局資源文件

暫定四個(gè)自定義attr

  • cl_contentLayoutId
  • cl_emptyLayoutId
  • cl_errorLayoutId
  • cl_loadingLayoutId

看命名就知道弄啥的了...

繼承RelativeLayout還是FrameLayout?

RelativeLayout & FrameLayout 都可以實(shí)現(xiàn)需求,但它們有所區(qū)別:RelativeLayout會(huì)measure兩次。
因此我選擇FrameLayout來實(shí)現(xiàn)。

選擇LayoutId還是ViewId?

可能您對我這個(gè)提法有點(diǎn)疑惑,啥是LayoutId,啥是ViewId?
LayoutId即對應(yīng)R.layout.xxx布局資源id
ViewId即對應(yīng)R.id.xxx頁面中view id

其實(shí)這兩個(gè)東東對應(yīng)兩個(gè)思路:
(1)viewid:即在ContentLayout下搞四個(gè)布局,分別設(shè)置一個(gè)id并作為那四個(gè)自定義屬性的值。
(2)layoutid:即搞幾個(gè)layout,作為那四個(gè)自定義屬性的值

對于思路一:我個(gè)人不太喜歡,這樣會(huì)讓ContentLayout子view眾多且層級復(fù)雜,不好調(diào)試,更不美觀
對于思路二:我很推崇,不同的狀態(tài)對應(yīng)單獨(dú)的布局文件

因此,我決定選擇LayoutId的方式實(shí)現(xiàn)。

如何實(shí)現(xiàn)?

選擇LayoutId后,需要做兩件事:

  • inflate->view
  • 將view作為ContentLayout的子view

后面的事,就是切換哪個(gè)view顯示的問題了。

想到的可以優(yōu)化的點(diǎn):延遲inflate,需要的時(shí)候才inflate。

 public QTContentLayout errorView(View errorView) {
        bindView(errorView, STATE_ERROR);
        return this;
}

content布局怎么搞?

ContentLayout中必定會(huì)有一個(gè)content布局,我們就沒必要搞一個(gè)單獨(dú)的layout??梢灾苯釉赾ontentlayout下搞一個(gè)子viewgroup。
默認(rèn)情況下,將Contentlayout的第一個(gè)子view作為contentView。
如何實(shí)現(xiàn)呢?
重寫onFinishInflate方法中:

 int childCount = getChildCount();
 if (childCount == 1) {
     contentView = getChildAt(0);
}

如何保存view的狀態(tài)?

保存Ui狀態(tài)一般是通過onSaveInstanceState()onRestoreInstanceState來實(shí)現(xiàn)。

 @Override
    protected Parcelable onSaveInstanceState() {
        Parcelable parcelable = super.onSaveInstanceState();
        SavedState savedState = new SavedState(parcelable);
        savedState.state = this.displayState;
        return savedState;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        SavedState savedState = (SavedState) state;
        super.onRestoreInstanceState(savedState.getSuperState());
        this.displayState = savedState.state;
        setDisplayState(this.displayState);
    }

如何使用?

 <cn.droidlover.qtcontentlayout.QTContentLayout
        android:id="@+id/contentLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="5dp"
        app:cl_emptyLayoutId="@layout/view_empty"
        app:cl_errorLayoutId="@layout/view_error"
        app:cl_loadingLayoutId="@layout/view_loading">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#854678"
            android:gravity="center"
            android:text="content"
            android:textColor="@android:color/white"
            android:textSize="28sp" />

    </cn.droidlover.qtcontentlayout.QTContentLayout>

蛋疼完畢,具體實(shí)現(xiàn)過程可看源碼。

XDroid:一個(gè)輕量級的Android快速開發(fā)框架。

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

相關(guān)閱讀更多精彩內(nèi)容

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