如何在嵌套滚动视图结束后停用父滚动视图的滚动?

4
我有一个嵌套的滚动视图在滚动视图内部,它可以工作,但我不希望当我在嵌套滚动视图内部滚动并到达顶部或底部时,自动继续滚动“父级”滚动视图的行为。我觉得这绝对是很烦人的。
新应用程序项目带有基本活动和内容_main.xml的内容。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        tools:showIn="@layout/activity_main"
        tools:context=".MainActivity">
    <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:layout_margin="5dp"
            android:background="@color/colorPrimary">

        <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Root"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                android:layout_margin="5dp"
                android:background="@color/colorAccent"/>

        <ScrollView
                android:id="@+id/scrollViewRoot"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@android:color/holo_orange_dark"
                android:paddingRight="40dp">
            <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:orientation="vertical"
                    android:layout_margin="5dp"
                    android:background="@color/colorPrimary">

                <TextView
                        android:text="Nested1"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content" android:id="@+id/textViewNested1"
                        android:layout_margin="5dp"
                        android:background="@color/colorAccent"/>
                <androidx.core.widget.NestedScrollView
                        android:layout_width="match_parent"
                        android:layout_height="1000dp" android:fillViewport="true"
                        android:background="@android:color/black">
                    <LinearLayout android:layout_width="match_parent"
                                  android:layout_height="2000dp"
                                  android:orientation="vertical"
                                  android:layout_margin="5dp"
                                  android:background="@color/colorPrimaryDark">
                        <TextView
                                android:text="TextView"
                                android:layout_width="match_parent"
                                android:layout_height="1800dp" android:id="@+id/textView3"
                                android:layout_margin="5dp"
                                android:background="@color/colorAccent"
                        />
                    </LinearLayout>
                </androidx.core.widget.NestedScrollView>
                <TextView
                        android:text="Nested2"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content" android:id="@+id/textViewNested2"
                        android:layout_margin="5dp"
                        android:background="@color/colorAccent"
                />
                <androidx.core.widget.NestedScrollView
                        android:layout_width="match_parent"
                        android:layout_height="1000dp" android:fillViewport="true"

                        android:background="@android:color/black">
                    <LinearLayout android:layout_width="match_parent"
                                  android:layout_height="2000dp"
                                  android:orientation="vertical"
                                  android:layout_margin="5dp"
                                  android:background="@color/colorPrimaryDark">
                        <TextView
                                android:text="TextView"
                                android:layout_width="match_parent"
                                android:layout_height="1800dp" android:id="@+id/textView4"
                                android:layout_margin="5dp"
                                android:background="@color/colorAccent"
                        />
                    </LinearLayout>
                </androidx.core.widget.NestedScrollView>

            </LinearLayout>

        </ScrollView>

    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

错误:如果顶部或底部被滚动到,内部滚动会导致父级滚动视图滚动。

正确:即使滚动到顶部或底部,内部滚动也无法滚动父级滚动视图。

1个回答

2

我认为这是不可能的。然而,您可以创建自己的NestedScrollView子类,并覆盖onNestedScroll()onNestedFling()来防止传递“未消耗”的滚动值。

最初的回答

class MyNestedScrollView(context: Context, attrs: AttributeSet?) : NestedScrollView(context, attrs) {

    override fun onNestedScroll(target: View, dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int, dyUnconsumed: Int, type: Int) {
        super.onNestedScroll(target, dxConsumed, dyConsumed, 0, 0, type)
    }

    override fun onNestedFling(target: View, velocityX: Float, velocityY: Float, consumed: Boolean): Boolean {
        return super.onNestedFling(target, velocityX, velocityY, true)
    }
}

onNestedScroll()中,我们拦截dxUnconsumeddyUnconsumed并将它们重写为0。在onNestedFling()中,我们拦截consumed并将其重写为true
这使得系统认为子视图始终消耗了所有滚动事件,因此当子视图滚动到边界时,父视图不会响应滚动事件。
现在我们只需要将其用作布局中的外部滚动视图即可:
<?xml version="1.0" encoding="utf-8"?>
<com.example.stackoverflow.MyNestedScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

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

        <!-- ... -->

        <android.support.v4.widget.NestedScrollView
            android:layout_width="match_parent"
            android:layout_height="your height here">

            <!-- ... -->

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

        <!-- ... -->

    </LinearLayout>

</com.example.playground.MyNestedScrollView>

请注意,以下操作具有潜在危险:如果您的布局可能导致子滚动视图填充整个屏幕,则无法“退出”子滚动视图。 - Ben P.
你好,非常感谢您的回答/建议。即使我很惊讶没有这个选项,但那听起来很有道理。当然,您指出的危险是正确的,这就是为什么我有一个右填充以确保我可以使用外部滚动条。 - Deacon Frost
我尝试了你的答案,将代码粘贴到MainActivity.kt的末尾,并尝试替换外部滚动区域和内嵌滚动区域为"MyNestedScroll",但结果仍然一样,应用程序在启动后立即关闭。你觉得这是为什么呢? - Deacon Frost
运行正常,太棒了!感谢Ben P.!外部ScrollView已被替换为我的“com.example.app05basic.MyNestedScrollView”,我第一次尝试只使用“MyNestedScrollView”显然不起作用 :) - Deacon Frost
很高兴能帮忙 :) - Ben P.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接