AppBarLayout RecycleView 点击事件 两次 响应

2,412 阅读1分钟

复现

开发过程中遇到一个问题,recyclerView 中快速滑动到尾部时,点击无响应,第二次点击生效。

查找原因

首先想到的就是焦点问题。控件中并无主动获取焦点行为的控件,理应没有这种问题,尝试主动获取焦点,无效。

问题最终放到recyclerView本身,监听recyclerView滑动事件输出log查看recyclerView状态。滑动结束后,recyclerView仍然处于滑动状态,尝试在recyclerView中滑动结束后主动设置状态,当dy为正,并且已经完全显示完成,则设置停止。

if (dy > 0) {
	LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
	int visibleItemCount = linearLayoutManager.getChildCount();
	int totalItemCount = linearLayoutManager.getItemCount();
	int pastVisibleItems = linearLayoutManager.findFirstVisibleItemPosition();

	if ((visibleItemCount + pastVisibleItems) >= totalItemCount) {
		if (!recyclerView.canScrollVertically(1)) {
			recyclerView.stopScroll();
		}
	}
}

发现有一定效果,仍然无法完全解决。

由该现象推测,一段时间后,recyclerView状态回归正常。尝试滑动后过一会点击,确实有效,该原因实锤。

搜索引擎检索后查找到有描述和AppBarLayout相关导致。原因是Google在修复滑动时引入的bug,谷歌给出了修复办法。

修复办法地址

解决办法

public class FixAppBarLayoutBehavior extends AppBarLayout.Behavior {

    public FixAppBarLayoutBehavior() {
        super();
    }

    public FixAppBarLayoutBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target,
            int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed,
                dxUnconsumed, dyUnconsumed, type);
        stopNestedScrollIfNeeded(dyUnconsumed, child, target, type);
    }

    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child,
            View target, int dx, int dy, int[] consumed, int type) {
        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);
        stopNestedScrollIfNeeded(dy, child, target, type);
    }

    private void stopNestedScrollIfNeeded(int dy, AppBarLayout child, View target, int type) {
        if (type == ViewCompat.TYPE_NON_TOUCH) {
            final int currOffset = getTopAndBottomOffset();
            if ((dy < 0 && currOffset == 0)
                    || (dy > 0 && currOffset == -child.getTotalScrollRange())) {
                ViewCompat.stopNestedScroll(target, ViewCompat.TYPE_NON_TOUCH);
            }
        }
    }
}

在xml或者代码中使用Behavior即可解决该问题