NestedScrollView 在 Nougat 上抛出停止错误(API 25)

NestedScrollView fling stopping bug on Nougat (API 25)

Nexus 5x (7.1.2) 和 Google Pixel (7.1.1) 上的 NestedScrollView fling 有一个奇怪的问题。在其他 OS 版本上它工作正常。

滑动动画有时会在抬起手指后立即停止。它卡住了,接下来的几次尝试也可能会停止。 为了重现它,你需要上下投掷几次。

在日志中,这些投掷在速度、方向等方面看起来几乎相同,所以我找不到这个错误的真正原因。

另外,NestedScrollView不一定要在CoordinatorLayout里面,也可以根本没有NestedScrollingChild

例如,此错误可通过以下 NestedScrollView children 之一重现:

1) LinearLayout 填充 TextViews

2) WebView

3) LinearLayout 填充了 RecyclerViews.

我知道 RecyclerViewCoordinatorLayout 内的行为可能存在的问题,但这不相关。 所以请不要提及任何

recyclerView.getLayoutManager().setAutoMeasureEnabled(true);
recyclerView.setNestedScrollingEnabled(false);

或类似的东西。

代码示例:

<android.support.v4.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="16dp"
            android:text="Put a super long text here"/>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="16dp"
            android:text="Put a super long text here"/>

    </LinearLayout>

</android.support.v4.widget.NestedScrollView>

所以这显然是 NestedScrollView 中的一个错误。 我已经为此做了一个解决方法,但仍在等待 Google 方面的正确修复。

https://github.com/Dimezis/FlingableNestedScrollView/

编辑:

看起来问题已在支持库 26.0.0-beta2 中修复

https://chris.banes.me/2017/06/09/carry-on-scrolling/

编辑 2: 虽然滚动现在工作正常,但在我的应用程序中我可以不断重现此错误:

https://issuetracker.google.com/issues/37051723

如果有人也遇到它,您可以在提到的线程中找到解决方法。

根据Animating a Scroll Gesture training guide,在覆盖 computeScroll() 时,在使用 mScroller.computeScrollOffset() 计算滚动视图的适当偏移量后,我们需要使用:

ViewCompat.postInvalidateOnAnimation(this);

为下一个滚动设置动画。 但是,在 NestedScrollView 中,computeScroll() 看起来像这样:

public void computeScroll() {
    if (mScroller.computeScrollOffset()) {
    ...     
    }
}

不请求下一个滚动动画!这意味着在使用mScroller.fling(...)之后,computeScroll()方法有时只会被调用一次,并且视图不会一直闪烁。

为了解决这个问题,我尝试用这种方式替换 computeScroll:

public void computeScroll(){
    if(mScroller.computeScrollOffset()){
       ...
       ViewCompat.postInvalidateOnAnimation(this); 
    }
}

这听起来可能不是一个好的解决方案,但目前它工作得很好。

最新版本的 NestedScrollView 添加了 ViewCompat.postInvalidateOnAnimation(this)。