ProgressFragment的簡單封裝

若蘭__明月發表於2018-01-03

###寫在前面 一般我們開發應用的時候,比如首頁或者詳情介面,當請求資料的時候,我們一般都會給使用者一個簡單的提示,比如加一個進度條或者彈出一個Dialog。但是有時候彈出Dialog的時候只是給使用者了一個提示,但是當出現錯誤之後,也只是簡單的一個Toast提示,並不能再次進行請求(有可能稍微做些處理,比如請求錯誤之後隱藏content佈局然後在顯示一個錯誤佈局),第一種情況體驗很是糟糕,第二種情況稍微好點,但是我們每次寫一個佈局都需要多寫錯誤佈局(或者寫一個公共的,然後在其他地方進行引用,但是有一點就是我們在每次的activity或者fragment使用的時候都需要寫入邏輯),造成不必要的程式碼冗餘。今天就來進行封裝一下,完成一個侵入式的ProgressFragment。 ###開始實現 ####第一步分析 我們首先要實現的封裝,能夠達到以下的幾個要求

  • 1、載入的時候顯示Loading狀態

  • 2、資料為空或者錯誤的時候顯示資料為錯誤或者其他提示

  • 3、正常情況顯示正常資料狀態

  • 4、當“資料為空或者錯誤狀態”的時候,可以點選進行重新請求資料 ####原理分析 看到那四個需要實現的條件,我們大致可以瞭解到,需要有三種佈局狀態***正常佈局狀態***、錯誤佈局狀態、***Loading狀態***有了這幾種狀態,我們就可以在請求的時候根據我們定義的以下方法(或者類似方法),然後控制不同佈局的顯示和載入

  • showLoading()方法中顯示***Loading狀態佈局***

  • showError()或者showNoData()方法顯示***錯誤狀態佈局***

  • 其餘正常狀態顯示***正常佈局狀態***(也就是剛開始這個佈局是顯示visiable)

####程式碼實現 有了分析,我們首先可以知道需要三種佈局(錯誤、載入、正常)

錯誤佈局

 <LinearLayout
        android:id="@+id/view_empty"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:visibility="gone">

        <TextView
            android:id="@+id/text_tip"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/empty_data"/>
    </LinearLayout>
複製程式碼

載入佈局

  <LinearLayout
        android:id="@+id/view_progress"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:gravity="center"
        android:orientation="vertical"
        android:visibility="gone">


        <ProgressBar
            android:id="@+id/progress"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>

        <TextView
            android:id="@+id/text_loading"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="@string/loading"/>

    </LinearLayout>
複製程式碼

正常佈局

 <FrameLayout
        android:id="@+id/view_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </FrameLayout>

複製程式碼

佈局完成之後,首先說明一下,他們三個的頂層佈局是FrameLayout(ViewGroup的子類) 然後看下邏輯程式碼怎麼實現的吧。

#####第一步就是找到佈局id

 @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        //跟佈局
        mRootView = (FrameLayout) inflater.inflate(R.layout.fragment_progress, container, false);
        //空佈局也就是錯誤佈局
        mViewEmpty = mRootView.findViewById(R.id.view_empty);
        //對錯誤佈局實現點選事件  完成載入出錯或者資料為空的時候  點選重新請求資料邏輯
        mViewEmpty.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onEmptyViewClick();
            }
        });
        //載入loading佈局
        mViewProgress = mRootView.findViewById(R.id.view_progress);
        //真實的佈局
        mViewContent = (FrameLayout) mRootView.findViewById(R.id.view_content);
        //載入出錯或者資料為空顯示的錯誤佈局的一個提示
        mEmptyTextView = (TextView) mRootView.findViewById(R.id.text_tip);
        return mRootView;
    }
複製程式碼

#####第二步確定什麼時候載入真實佈局

  @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        this.mApplication = (CNMarketApplication) getActivity().getApplication();
        setupAcitivtyComponent(mApplication.getAppComponent());
        //載入真實的佈局
        setRealContentView();
        //用於初始化佈局控制元件  這裡也可以不寫  因為我們使用了ButterKnife實現對控制元件的註解
        init();
        //用於子類實現  請求資料方法
        initData();
    }
複製程式碼

setRealContentView()方法

 /**
     * 設定真正的佈局
     */
    private void setRealContentView() {
        View realContentView = LayoutInflater.from(getActivity()).inflate(setLayout(), mViewContent, true);
        mUnbinder = ButterKnife.bind(this, realContentView);
    }
複製程式碼

#####第三步控制三種佈局的顯示 我們這個時候要寫控制三種佈局的顯示和隱藏的邏輯,這個時候可能有人會這樣寫

    /**
     * 顯示載入loading佈局
     */
    public void showProgressView(){
        mViewProgress.setVisibility(View.VISIBLE);
        mViewEmpty.setVisibility(View.GONE);
        mViewContent.setVisibility(View.GONE);
    }
複製程式碼

然後在寫剩餘的兩種邏輯,這樣寫沒有錯,但是感覺程式碼是有點冗餘而且也不太好看,前面我們提到過,跟佈局是一個FrameLayout,屬於ViewGroup的子類,那麼他就有*getChildCount()*方法獲取子view那麼我們就可以這樣寫邏輯了。

  /**
     * 判斷要顯示的子view  正常佈局  錯誤佈局  loading佈局  根據傳入的viewId
     *
     * @param viewId 需要顯示的viewid
     */
    public void showView(int viewId) {
        int childCount = mRootView.getChildCount();
        for (int i = 0; i < childCount; i++) {
            if (mRootView.getChildAt(i).getId() == viewId) {
                mRootView.getChildAt(i).setVisibility(View.VISIBLE);
            } else {
                mRootView.getChildAt(i).setVisibility(View.GONE);  //隱藏
            }
        }
    }
複製程式碼

然後接下來這樣寫三個邏輯


    /**
     * 顯示進度條view
     */
    public void showProgressView() {
        showView(R.id.view_progress);
    }

    /**
     * 顯示真實佈局view
     */
    public void showContentView() {
        showView(R.id.view_content);
    }

    /**
     * 顯示資料為空view
     */
    public void showEmptyView() {
        showView(R.id.view_empty);
    }

    /**
     * 顯示資料為空view
     */
    public void showEmptyView(int resId) {

        showView(R.id.view_empty);
        mEmptyTextView.setVisibility(View.VISIBLE);
        mEmptyTextView.setText(resId);
    }

    /**
     * 顯示資料為空view
     */
    public void showEmptyView(String msgId) {
        showView(R.id.view_empty);
        mEmptyTextView.setVisibility(View.VISIBLE);
        mEmptyTextView.setText(msgId);
    }

複製程式碼

####第四步子類使用 這個時候基本邏輯就差不多完事了,然後剩餘的就需要子Fragment或者子activity進行繼承和重寫方法,實現邏輯了。比如

重新請求資料

    @Override
    public void onEmptyViewClick() {
        super.onEmptyViewClick();
        //重新請求資料
        mPresenter.requestDatas();
    }
複製程式碼

顯示錯誤和資料為空邏輯

@Override
    public void showNoData() {
        //showError("沒有資料進行展示");
        showEmptyView("沒有資料進行展示");
        Toast.makeText(getActivity(), "沒有資料進行展示", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void showError(String msg) {
       // showError(msg);
        showEmptyView(msg);
        Toast.makeText(getActivity(), "伺服器開小差了" + msg, Toast.LENGTH_SHORT).show();
    }
複製程式碼

這裡整體邏輯就算實現了,完整的程式碼我就不貼了,這裡直接給出git地址

*一個集RxJava+Retrofit+MVP+Dagger2的app

相關文章