1. 程式人生 > >優雅的解決SwipeRefreshLayout和ListView的EmptyView共存衝突的問題(全網獨創)

優雅的解決SwipeRefreshLayout和ListView的EmptyView共存衝突的問題(全網獨創)

故事背景

自從Android Material Design出來之後,以其優雅酷炫的效果深受廣大使用者的喜愛,我個人也非常喜歡其漂亮的介面,特別是SwipeRefreshLayout,呵呵看臉的世界ing
言歸正傳最近有個專案需要用到SwipeRefreshLayout巢狀一個listView,該listview不需要上拉載入,就是隻需要簡單的下拉重新整理即可,於是二話不說,直接SwipeRefreshLayout巢狀ListView,嗯,效果完美,佈局程式碼如下

<android.support.v4.widget.SwipeRefreshLayout  
    android:id="@+id/swipe_layout"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent">  
  
        <ListView  
            android:id="@+id/listview"  
            android:layout_width="match_parent"  
            android:layout_height="wrap_content"  
            android:background="@color/white"/>  
  
</android.support.v4.widget.SwipeRefreshLayout>  
但是考慮到當listview沒有資料的話應該顯示一個提示,比如“暫無資料,下拉重新整理”之類的提示,於是把佈局改成下面這樣:
<android.support.v4.widget.SwipeRefreshLayout  
        android:id="@+id/swipe_layout"  
        android:layout_width="match_parent"  
        android:layout_height="match_parent">  
  
            <ListView  
                android:id="@+id/listview"  
                android:layout_width="match_parent"  
                android:layout_height="wrap_content"  
                android:background="@color/white"/>  
            <include layout="@layout/empty_layout"/>  
  
</android.support.v4.widget.SwipeRefreshLayout> 
empty_layout.xml
<TextView  
    xmlns:android="http://schemas.android.com/apk/res/android"  
    android:id="@+id/empty_view"  
    android:layout_width="fill_parent"  
    android:layout_height="fill_parent"  
    android:gravity="center"  
    android:text="@string/no_content_refresh"/>

然後java程式碼中為ListView設定一下EmptyView,編譯執行,當listview無資料的時候,發現設定無效!!!  

網上查詢資料說是SwipeRefreshLayout只能有一個子View,於是按照網上方法改成下面這樣:

<android.support.v4.widget.SwipeRefreshLayout  
        android:id="@+id/swipe_layout"  
        android:layout_width="match_parent"  
        android:layout_height="match_parent">  
  
        <FrameLayout  
            android:layout_width="match_parent"  
            android:layout_height="match_parent">  
            <ListView  
                android:id="@+id/listview"  
                android:layout_width="match_parent"  
                android:layout_height="wrap_content"  
                android:background="@color/white"/>  
            <include layout="@layout/empty_layout"/>  
        </FrameLayout>  
  
</android.support.v4.widget.SwipeRefreshLayout>

更大的問題來了當SwipeRefreshLayout只有ListView一個子view的時候是沒有任何問題的,但如果不是一個子view就會出現問題了,向上滑動ListView一切正常,向下滑動的時候就會出現還沒有滑倒ListView頂部就觸發下拉重新整理的動作了。加了empty_layout之後listview根本無法下拉,每次下拉都是觸發SwipeRefreshLayout的下拉方法。

於是參考了各種方案,如下

重寫SwipeRefreshLayout http://www.eoeandroid.com/forum.php?mod=viewthread&tid=914273

設定listview的setOnScrollListener  https://www.2cto.com/kf/201702/601860.html

以及設定onTouchListener

mListView.setOnTouchListener(new View.OnTouchListener() {  
            @Override  
            public boolean onTouch(View v, MotionEvent event) {  
                if (event.getAction() == MotionEvent.ACTION_MOVE) {  
                    Log.d("Measure", "listview.getListPaddingTop():"+mListView.getListPaddingTop()+  
                            " listview.getTop():"+mListView.getTop()+"listview.getChildAt(0).getTop():"+mListView.getChildAt(0).getTop());  
                    if (mListView.getFirstVisiblePosition() == 0 &&  
                            mListView.getChildAt(0).getTop() >= mListView.getListPaddingTop()) {  
                        mRefreshLayout.setEnabled(true);  
                        Log.d("TAG", "reach top!!!");  
                    }else mRefreshLayout.setEnabled(false);  
                }  
                return false;  
            }  
        });

發現設定onTouchListener和setOnScrollListener  效果差不多,listview確實能夠下滑了,但是有一個小bug,好像SwipeRefreshLayout 下拉的時候有點不靈光,有時候需要下拉兩三次才能夠觸發下拉重新整理,log一直輸出  
Got ACTION_MOVE event but don't have an active pointer id
然後效果類似下面這樣:

無法觸發下拉,嘗試了兩三次之後,又正常了,這個效果還是不太滿意,so,受到網友的啟發,得到了下面的方案:

終極解決方案:

其實只需要把佈局稍微改變一下即可完美解決,修改之後的佈局如下:

<FrameLayout  
        android:layout_width="match_parent"  
        android:layout_height="match_parent">  
  
        <include layout="@layout/empty_layout"/>  
  
        <android.support.v4.widget.SwipeRefreshLayout  
            android:id="@+id/swipe_layout"  
            android:layout_width="match_parent"  
            android:layout_height="match_parent">  
  
            <ListView  
                android:id="@+id/listview"  
                android:layout_width="match_parent"  
                android:layout_height="wrap_content"  
                android:background="@color/white"/>  
        </android.support.v4.widget.SwipeRefreshLayout>  
    </FrameLayout>  
其他的都不用變,這個佈局非常巧妙的解決了以上難題,應該是全網最優雅的一種方式了,不敢獨享,遂熬夜拿出來跟大家一起共享~~~~~ 
最後放上一張效果圖