背景:高版本的编译环境中,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); } }); }