CoordinatorLayout + AppBarLayout + SwipeRefreshLayout在eclipse上使用的方法和問題記錄
專案開始使用的eclipse進行開發。
需求
在做一個介面時
狀態列下面是標題欄,黃色的圖片是頭部的viewpager,再下面是fragment的名字的tab,tab下面是viewpager,viewpager中是fragment,
要求是上拉時整體上滑,tab欄到頂部時停留列表繼續上滑, 下拉時列表下滑顯示完全以後,再下拉頭部檢視,這個介面結構並不難做,我開始用的一個自定義元件,以前做demo時使用過,
就是這兩個,單獨使用並沒有問題,但是我的3個fragment都有重新整理需求,所以我想把SwipeRefreshLayout套在整個佈局的外面,然後通過介面將重新整理事件傳遞到fragment中去,問題出現了,下拉上拉各種衝突,鑑於重點不是這個就不描述了,類似的衝突後面也會出現,再說解決方法。重點是CoordinatorLayout + AppBarLayout在eclipse中的使用,和巢狀重新整理衝突的解決。
在eclipse中使用:
開始說了專案用的eclipse,所以並不能像網上一片片的compile來使用design庫,我就從sdk中複製了design庫出來,當做library引入專案中,然後使用:
有flag,有behavior,有正確的巢狀,但是fragment中的recyclerview上滑時,標記了flag的view並沒有上滑隱藏,單獨滑動這個view是可以的,始終確定不了原因,然後就想著是版本問題嗎,因為我使用的是recyclerview是以前專案用的jar,可能比較老呢? 於是複製了sdk中的recyclerview出來當庫引入,好了... ,現在的佈局是CoordinatorLayout + AppBarLayout,實現了和自定義佈局ScrollableLayout相似的功能,然後加上SwipeRefreshLayout,又出現了滑動衝突的問題,使用ScrollableLayout時這個問題解決過,但是可能因為自定義view本身邏輯不嚴密吧,偶爾還是有bug,所以才使用design庫,也正好學習下里面的元件,出現這個衝突時,百度了下,AppBarLayout
自帶了一個監聽器OnOffsetChangedListener ,用來告訴你他的偏移量,只要計算這個偏移量然後設定swiperefreshlayout的enable屬性,讓重新整理元件在appbarlayout沒有滑下來時不活動就能解決。
實際使用中的問題:
但是實際使用時並沒有這麼簡單。fragment切換時的狀態變化,recyclerview的item上間距等等都會影響,舉個例子吧,fragment 1 的recyclerview上拉,appbarlayout中的帶flag的view隱藏了,swipe的enable=false, 然後切換到fragment 2 , 2中的recyclerview下拉,吧appbarlayout中的view拉下來,這時OnOffsetChangedListener
監聽器的偏移量是0,swipe的enable屬性=true,表示是可以重新整理的,然後又切換到fragment 1, 1中的recyclerview並沒有在頂部,應該是不能重新整理的,但是swipe的enable是true,所以他重新整理了,類似的衝突還有其他情況,我直接說解決的辦法吧。
解決過程:
使用了兩個監聽器,一個是自定義的監聽AppBarLayout偏移量的OnOffsetChangedListener,另一個是fragment切換時獲取其中的recyclerview物件的監聽器OnCurrentRvListener,
AppBarOffsetChangedListener 綜合判斷偏移量,recyclerview是否滑動到頂部,來設定是否允許重新整理,
RvTop.isRecyclerViewTop(listener.getRv(),listener.getTopSpec()) 這個方法就是判斷recyclerview是否滑動到頂部了,
OnCurrentRvListener 監聽室由viewpager中的fragment實現,返回fragment中的recyclerview物件和recyclerview的item上間距。
AppBarLayout便宜量的監聽器AppBarOffsetChangedListener初始化時傳入了swipeRefreshLayout的物件,但是他持有的OnCurrentRvListener 的物件在fragment切換時是會改變的,所以使用時應該動態設定AppBarOffsetChangedListener中的OnCurrentRvListener 的物件。
setCurrent()就是fragment切換的方法,OnCurrentRvListener 是由fragment實現的,所以OnCurrentRvListener 物件的初始化是在setCurrent()方法中,
當fragment切換時,重新獲取OnCurrentRvListener 物件並設定到AppBarOffsetChangedListener中去,這樣AppBarLayout監聽器偏移量變化時拿到的才是當前fragment中的recyclerview物件;
加上這兩個監聽器以後解決了一部分衝突,但並沒有完全解決。這個最終還是依靠AppBarLayout的偏移量監聽器來設定是否允許重新整理的,但是這個監聽器有時並不會觸發,所以有時還需要主動去觸發監聽器,上圖,在setCurrent()方法中切換fragment時主動觸發一下,呼叫了setSrlState()方法
public void setSrlState(){
if(offsetListener != null){
offsetListener.onOffsetChanged(mAppBarLayout, mAppBarLayout.getTop());
}
}
再在recyclerview的OnScrollListener中設定,
if (llManager.findFirstVisibleItemPosition() == 0) {
mRecordFragment.setSrlState();
}
當顯示第一個item時又主動去呼叫。
到這就差不多解決了我用了一段時間沒發現有衝突了,是過了一段時間才寫的,所以哪裡有遺漏以後再補吧,
其他情況
CoordinatorLayout + AppBarLayout的簡單使用網上一大把就不粘了,
另外做這塊的時候發現水平滑動本來是觸發viewpager左右滑動的,但是偏了一點就會觸發重新整理,所以自定義了viewpager 來解決這個滑動衝突,附上程式碼,思路就是 通過setSrl()方法把SwipeRefhreshlayout物件傳到viewpager中,然後在dispatchTouchEvent事件中獲取手指按下的座標,在onTouchEvent的move事件中判斷手指滑動的角度,設定是否允許重新整理。在up和cancel中還原swiperefreshLayout物件的狀態。