@Override
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
boolean headerScrollUp = dy > 0 && getScrollY() < mNestedScrollHeight;
boolean headerScrollDown = dy < 0 && getScrollY() > 0 && !target.canScrollVertically(-1);
if (headerScrollUp || headerScrollDown) {
scrollBy(0, dy);
consumed[1] = dy;
}
super.onNestedPreScroll(target, dx, dy, consumed, type);
}
代码类似上面这样,mNestedScrollHeight是Banner的高度。然后写好代码Run一下,嗯?没反应?不生效?what fuck?是我的逻辑不对吗?不可能啊?不禁陷入了程序猿的沉思。
DEBUG一下吧。在onNestedPreScroll里面打个断点,发现根本没执行进来!这就很奇怪了,又查一查网上的大家的解决方案,大家不都是这么做的吗?于是又陷入了自我怀疑。
折腾了一下午,还是没折腾出来,期间还用其他方案来做嵌套滑动,效果都实现差不多了,就是实现方式非常的ugly。秉承着一个稍微有点代码洁癖的程序猿的自觉,我还是决定搞清楚为啥onNestedPreScroll没有被调用。所以终极解决方案就是,read the fucking source code!
由于这里嵌套滑动的子布局是RecyclerView,所以消费滑动的事件是由RecyclerView发出的,然后在RecyclerView的onTouchEvent,在ACTION_DOWN中发出的startNestedScroll,具体实现是在NestedScrollingChildHelper。通过再次DEBUG,我确定了RecyclerView的ViewParent确实是我自定义的StickyNestedScrollView(继承自NestedScrollView),吃了个定心丸。然后回到RecyclerView的onTouchEvent,在ACTION_MOVE中调用了dispatchNestedPreScroll,向嵌套父布局发起嵌套滑动的事件,交给父布局先处理。dispatchNestedPreScroll的具体实现也是在NestedScrollingChildHelper,然后在里面调用了ViewParentCompat.onNestedPreScroll,看一下ViewParentCompat.onNestedPreScroll的源码。
public static void onNestedPreScroll(ViewParent parent, View target, int dx, int dy, int[] consumed, int type) {
if (parent instanceof NestedScrollingParent2) {
((NestedScrollingParent2)parent).onNestedPreScroll(target, dx, dy, consumed, type);
} else if (type == 0) {
if (VERSION.SDK_INT >= 21) {
try {
parent.onNestedPreScroll(target, dx, dy, consumed);
} catch (AbstractMethodError var7) {
Log.e("ViewParentCompat", "ViewParent " + parent + " does not implement interface " + "method onNestedPreScroll", var7);
}
} else if (parent instanceof NestedScrollingParent) {
((NestedScrollingParent)parent).onNestedPreScroll(target, dx, dy, consumed);
}
}
}
NestedScrollView实现的是NestedScrollingParent2,所以这里调用了onNestedPreScroll(target, dx, dy, consumed, type),看到这里,就发现,这个方法怎么和我重写的方法不太一样啊?
然后继续看了一下继承关系,NestedScrollingParent2接口继承自NestedScrollingParent接口,然后增加了一同名的函数onNestedPreScroll,但是增加了一个参数;NestedScrollView实现了NestedScrollingParent2接口。而最终调用的是NestedScrollingParent2的onNestedPreScroll(target, dx, dy, consumed, type)方法。所以,我们需要继承NestedScrollView,重写NestedScrollingParent2的onNestedPreScroll(target, dx, dy, consumed, type)方法,在里面做处理才可以。就因为这个同名方法,可坑死我了,以后遇到类似的事情可得长点心了。