使用DataBinding來(lái)設(shè)置空狀態(tài)

寫在前面

在平時(shí)的開發(fā)之中纯续,我們需要對(duì)于數(shù)據(jù)加載的情況進(jìn)行展示:

  • 空數(shù)據(jù)
  • 網(wǎng)絡(luò)異常
  • 加載中等等情況

現(xiàn)在設(shè)置頁(yè)面狀態(tài)的方式有多種,由于筆者近期一直在使用databinding蝶俱,而數(shù)據(jù)綁定通過(guò)改變模型來(lái)展示view的方式和狀態(tài)頁(yè)的設(shè)置也滿契合的。

所以這里就講講使用databinding來(lái)設(shè)置android中的各種狀態(tài)頁(yè)饥漫。很簡(jiǎn)單榨呆,先看看效果

screnshot.gif

沒(méi)了解過(guò)databinding的可以先了解一下

Data Binding(數(shù)據(jù)綁定)用戶指南

首先

在app的build.gradle文件中開啟databinding

android{
    ...
    dataBinding {
        enabled = true
    }
}

我們先定義一些用于狀態(tài)的注解EmptyState

/**
 * 頁(yè)面描述:空狀態(tài)
 * <p>
 * Created by ditclear on 2017/2/24.
 */
@IntDef({NORMAL, PROGRESS, EMPTY, NET_ERROR, NOT_AVAILABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface EmptyState {

    int NORMAL = -1;  //正常
    int PROGRESS = -2;//顯示進(jìn)度條
    
    int EMPTY = 11111; //列表數(shù)據(jù)為空
    int NET_ERROR = 22222;  //網(wǎng)絡(luò)未連接
    int NOT_AVAILABLE = 33333; //服務(wù)器不可用
    
    //...各種頁(yè)面的空狀態(tài),可以自己定義庸队、添加

}

再自定義一個(gè)異常EmptyException用于顯示我們需要的狀態(tài)信息

/**
 * 頁(yè)面描述:異常
 * <p>
 * Created by ditclear on 2017/3/5.
 */
public class EmptyException extends Exception {

    private int code;

    public EmptyException(@EmptyState int code) {
        super();
        this.code = code;
    }


    @EmptyState
    public int getCode() {
        return code;
    }

    public void setCode(@EmptyState int code) {
        this.code = code;
    }
}

現(xiàn)在愕提,大多數(shù)展示狀態(tài)頁(yè)的控件都會(huì)提供

  1. 加載中的進(jìn)度條
  2. 錯(cuò)誤信息
  3. 空狀態(tài)
  4. ...

所以我們的目標(biāo)也是顯示這些

布局

以數(shù)據(jù)綁定的形式進(jìn)行布局,使用StateModel來(lái)控制狀態(tài)頁(yè)展示的消息

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    >

    <data>

        <import type="android.view.View"/>

        <variable
            name="stateModel"
            type="com.ditclear.app.state.StateModel"/>
    </data>

    <RelativeLayout
        android:id="@+id/rv_empty_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/background"
        android:clickable="true"
        android:focusableInTouchMode="true"
        android:visibility="@{stateModel.empty?View.VISIBLE:View.GONE}">

        <android.support.v4.widget.ContentLoadingProgressBar
            style="?android:attr/progressBarStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:visibility="@{stateModel.progress?View.VISIBLE:View.GONE}"/>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_alignParentBottom="true"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:gravity="center"
            android:orientation="vertical"
            android:visibility="@{stateModel.progress?View.INVISIBLE:View.VISIBLE}">

            <ImageView
                android:id="@+id/none_data"
                android:layout_width="345dp"
                android:layout_height="180dp"
                android:scaleType="fitCenter"
                android:src="@{stateModel.emptyIconRes}"/>


            <TextView
                android:layout_width="wrap_content"
                android:layout_height="25dp"
                android:layout_below="@+id/none_data"
                android:layout_centerHorizontal="true"
                android:text="@{stateModel.currentStateLabel}"
                android:textSize="16sp"/>


        </LinearLayout>
    </RelativeLayout>
</layout>

布局文件中有幾個(gè)方法

  • empty 用于控制狀態(tài)頁(yè)是顯示還是隱藏皿哨,數(shù)據(jù)加載正常(即狀態(tài)為NORMAL)的時(shí)候隱藏,否則展示
  • isProgress 是否顯示加載中纽谒,如果顯示進(jìn)度條(即狀態(tài)為PROGRESS)证膨,就隱藏異常頁(yè)
  • emptyIconRes 顯示狀態(tài)的圖片信息
  • currentStateLabel 顯示狀態(tài)的文字消息

我們定義狀態(tài)的ViewModel ,就叫StateModel鼓黔,來(lái)控制狀態(tài)

/**
 * 頁(yè)面描述:狀態(tài)頁(yè)面設(shè)置模型
 * <p>
 * Created by ditclear on 2017/2/24.
 */

public class StateModel extends BaseObservable {

    private Context mContext = MyApp.instance();

    @EmptyState
    private int emptyState = EmptyState.NORMAL;

    private boolean empty;

    public int getEmptyState() {
        return emptyState;
    }

    /**
     * 設(shè)置狀態(tài)
     *
     * @param emptyState
     */
    public void setEmptyState(@EmptyState int emptyState) {
        this.emptyState = emptyState;
        notifyChange();
    }

    /**
     * 顯示進(jìn)度條
     *
     * @return
     */
    public boolean isProgress() {
        return this.emptyState == EmptyState.PROGRESS;
    }

    /**
     * 根據(jù)異常顯示狀態(tài)
     *
     * @param e
     */
    public void bindThrowable(Throwable e) {
        if (e instanceof EmptyException) {
            @EmptyState
            int code = ((EmptyException) e).getCode();

            setEmptyState(code);
        }
    }

    public boolean isEmpty() {
        return this.emptyState != EmptyState.NORMAL;
    }

    /**
     * 空狀態(tài)信息
     *
     * @return
     */
    @Bindable
    public String getCurrentStateLabel() {

        switch (emptyState) {
            case EmptyState.EMPTY:
                return mContext.getString(R.string.no_data);
            case EmptyState.NET_ERROR:
                return mContext.getString(R.string.please_check_net_state);
            case EmptyState.NOT_AVAILABLE:
                return mContext.getString(R.string.server_not_avaliabe);
            default:
                return mContext.getString(R.string.no_data);
        }
    }

    /**
     * 空狀態(tài)圖片
     *
     * @return
     */
    @Bindable
    public Drawable getEmptyIconRes() {
        switch (emptyState) {
            case EmptyState.EMPTY:
                return ContextCompat.getDrawable(mContext, R.drawable.ic_visibility_off_green_400_48dp);
            case EmptyState.NET_ERROR:
                return ContextCompat.getDrawable(mContext, R.drawable.ic_signal_wifi_off_green_400_48dp);
            case EmptyState.NOT_AVAILABLE:
                return ContextCompat.getDrawable(mContext, R.drawable.ic_cloud_off_green_400_48dp);
            default:
                return ContextCompat.getDrawable(mContext, R.drawable.ic_visibility_off_green_400_48dp);
        }
    }

}

很普通的視圖模型央勒,主要有幾個(gè)用于判斷狀態(tài)顯示的方法

  • bindThrowable 根據(jù)異常顯示狀態(tài)
  • setEmptyState 方法用來(lái)設(shè)置當(dāng)前的狀態(tài),通過(guò)notifyChange來(lái)通知布局文件改變
下面講講實(shí)際運(yùn)用:

activity或者fragment布局中澳化,添加狀態(tài)頁(yè)的布局

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <import type="android.view.View"/>

        <variable
            name="stateModel"
            type="com.ditclear.app.state.StateModel"/>

    </data>

    <com.ditclear.app.ScrollChildSwipeRefreshLayout
        android:id="@+id/refresh_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <RelativeLayout
            android:id="@+id/container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">


            <android.support.v4.widget.NestedScrollView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:fillViewport="false"
                android:overScrollMode="always"
                android:visibility="@{stateModel.empty?View.GONE:View.VISIBLE}">

                <TextView
                    android:id="@+id/content_tv"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:gravity="center"/>


            </android.support.v4.widget.NestedScrollView>


            <include
                layout="@layout/widget_layout_empty"
                app:stateModel="@{stateModel}"/>

        </RelativeLayout>
    </com.ditclear.app.ScrollChildSwipeRefreshLayout>
</layout>

最后在activity或者fragment中我們只需要通過(guò)state.bindThrowable()state.setEmptyState()方法便可以輕松設(shè)置各種各樣的狀態(tài)崔步。

loadData().subscribe(new Subscriber<List<Contributor>>() {

    @Override
    public void onStart() {
        super.onStart();
        if (!mMainBinding.refreshLayout.isRefreshing()) {
            mStateModel.setEmptyState(EmptyState.PROGRESS);
        }
    }

    @Override
    public void onCompleted() {
        mStateModel.setEmptyState(EmptyState.NORMAL);

    }

    @Override
    public void onError(Throwable e) {
        mMainBinding.refreshLayout.setRefreshing(false);
        mStateModel.bindThrowable(e);
        Toast.makeText(MainActivity.this, mStateModel.getCurrentStateLabel(), Toast.LENGTH_SHORT).show();


    }

    @Override
    public void onNext(List<Contributor> contributors) {
        mMainBinding.refreshLayout.setRefreshing(false);
        if (contributors == null || contributors.isEmpty()) {
            onError(new EmptyException(EmptyState.EMPTY));
        } else {
            mMainBinding.contentTv.setText(contributors.toString());
        }
    }
});

寫在最后

對(duì)于要使用數(shù)據(jù)來(lái)控制視圖狀態(tài)的,使用databinding實(shí)在是一個(gè)事半功倍的方式缎谷。而且也十分容易理解井濒。

最后github地址:https://github.com/ditclear/StateBinding

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市列林,隨后出現(xiàn)的幾起案子瑞你,更是在濱河造成了極大的恐慌,老刑警劉巖希痴,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件者甲,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡砌创,警方通過(guò)查閱死者的電腦和手機(jī)虏缸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門鲫懒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人刽辙,你說(shuō)我怎么就攤上這事窥岩。” “怎么了扫倡?”我有些...
    開封第一講書人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵谦秧,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我撵溃,道長(zhǎng)疚鲤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任缘挑,我火速辦了婚禮集歇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘语淘。我一直安慰自己诲宇,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開白布惶翻。 她就那樣靜靜地躺著姑蓝,像睡著了一般。 火紅的嫁衣襯著肌膚如雪吕粗。 梳的紋絲不亂的頭發(fā)上纺荧,一...
    開封第一講書人閱讀 51,443評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音颅筋,去河邊找鬼宙暇。 笑死,一個(gè)胖子當(dāng)著我的面吹牛议泵,可吹牛的內(nèi)容都是我干的占贫。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼先口,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼型奥!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起碉京,我...
    開封第一講書人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤桩引,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后收夸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坑匠,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年卧惜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了厘灼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片夹纫。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖设凹,靈堂內(nèi)的尸體忽然破棺而出舰讹,到底是詐尸還是另有隱情,我是刑警寧澤闪朱,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布月匣,位于F島的核電站,受9級(jí)特大地震影響奋姿,放射性物質(zhì)發(fā)生泄漏锄开。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一称诗、第九天 我趴在偏房一處隱蔽的房頂上張望萍悴。 院中可真熱鬧,春花似錦寓免、人聲如沸癣诱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)撕予。三九已至,卻和暖如春蜈首,著一層夾襖步出監(jiān)牢的瞬間实抡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工疾就, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人艺蝴。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓猬腰,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親猜敢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子姑荷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 寫在前面 這是使用DataBinding來(lái)設(shè)置空狀態(tài)的第二篇,在上一篇中介紹了基本的綁定空狀態(tài)的操作缩擂,而這一篇將在...
    ditclear閱讀 1,259評(píng)論 0 1
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,116評(píng)論 25 707
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理鼠冕,服務(wù)發(fā)現(xiàn),斷路器胯盯,智...
    卡卡羅2017閱讀 134,656評(píng)論 18 139
  • 印度海軍的“貝特瓦”號(hào)導(dǎo)彈護(hù)衛(wèi)艦在印度孟買港駛出船塢時(shí)傾覆懈费,導(dǎo)致2人死亡,14人受傷博脑。 印度海軍消息稱憎乙,該艦排水量...
    L大魔王kimi閱讀 365評(píng)論 0 0
  • 假如生活不能給你快樂(lè)票罐,那就自己給自己快樂(lè)∨⒈撸——題記 生活總是充滿著無(wú)奈與艱辛该押,各式各樣的,層出不窮阵谚。 有沒(méi)有一瞬間...
    余美魚閱讀 266評(píng)論 2 3