背景:高版本的編譯環境中,SwipeRefreshLayout和RecyclerView並不存在滑動衝突問題,而我恰恰手裏有個target是22的項目,當我按照正常的邏輯寫完界面後,使用app發現滑動整個列表時兩個控件發生衝突,本着快速解決上線任務的原則,直接百度.
網上的完美解決方案如下:
RecyclerView.OnScrollListener(){ @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { int topRowVerticalPosition = (recyclerView == null || recyclerView.getChildCount() == 0) ? 0 : recyclerView.getChildAt(0).getTop(); swipeRefreshLayout.setEnabled(topRowVerticalPosition >= 0); } @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); } });
使用完上面的代碼,依舊會出現bug:
從底部往回滑動時,如果當前頁面內可看見的第一個item剛好完整出現在界面上,這個時候繼續回滑,會出現觸發SwipeRefreshLayout的手勢 (該bug因爲操作難度的關係並不容易出現,但多操作幾次肯定會出現的)。
出現的原因:
是由於雖然recyclerView.getChildAt(0)取到的是第一個childView,但是由於RecyclerView自身的複用問題,第一個childView可能會被多次複用,如果僅僅判斷第一個childView的top是否大於等於0便會出現上述bug
解決方案:
如果firstChild處於列表的第一個位置,且top>=0,則下拉刷新控件可用
SwipeRefreshLayout layout) { rv.setOnScrollListener(new RecyclerView.OnScrollListener() { View firstChild; @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { if (recyclerView != null && recyclerView.getChildCount() > 0) { firstChild = recyclerView.getChildAt(0); } int firstChildPosition = firstChild == null ? 0 : recyclerView.getChildLayoutPosition(firstChild); layout.setEnabled(firstChildPosition == 0 && firstChild.getTop()>=0);//如果firstChild處於列表的第一個位置,且top>=0,則下拉刷新控件可用 } @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); } }); }