canScrollVertically和scrollBy的使用问题

最近项目使用CoordinatorLayout + Webview实现文章详情页上拉折叠头部效果,由于Webview并不支持app:layout_behavior,于是在Webview外套了一层NestScrollView, 由NestScrollView支持app:layout_behavior,然后重写NestScrollView的dispatchNestedScroll来控制Wevview的滚动,一开始的实现是

```

val canScroll =mWebView.canScrollVertically(dy)

if (canScroll) {

    ...

    mWebView.scrollBy(dxUnconsumed, dy)

    ...

    return true

}

```

然后发现往上滚时,mWebView顶部的一些内容滚不下来了,而且canScrollVertically返回false

后来通过一番研究,发现这是View的一个坑(也算是View的一个bug)

View内部有个变量mScrollY记录当前滚动距离,当scrollBy(dxUnconsumed, dy)中的dy+mScrollY < 0 时,scrollBy不会进行任何实际滚动,但同时它却会把mScrollY设为为dy+mScrollY

这就导致之后怎么滚都滚不下来(此时dy < 0)

因为canScrollVertically()的实现是:

```

public boolean canScrollVertically(int direction) {

final int offset = computeVerticalScrollOffset();

    final int range = computeVerticalScrollRange() - computeVerticalScrollExtent();

    if (range ==0)return false;

    if (direction <0) {

return offset >0;

    }else {

return offset < range -1;

    }

}

protected int computeVerticalScrollOffset() {

return mScrollY;

}

```

当最后一次滚动的dy < -mScrollY 时, mScrollY = dy+mScrollY, mScrollY变为负数,导致之后的往上滚时canScrollVertically都是返回false。

问题解决的方法是实现dispatchNestedScroll改为以下代码

```

val canScroll =mWebView.canScrollVertically(dy)

if (canScroll) {

    ...

    if (dy < 0) {

        dy = -min(-dy, mWebView.computeVerticalScrollOffset())

        mWebView.view.scrollBy(dxUnconsumed, dy)

        return true

    }

    ...

    return true

}

```

你可能感兴趣的:(canScrollVertically和scrollBy的使用问题)