防止底部菜单祖先视图滚动

10

我有一个包含两个 NestedScrollViewCoordinatorLayout,其中一个具有 ScrollingViewBehavior,另一个具有 BottomSheetBehavior 并扮演了 BottomSheet 的角色。问题是当我拖动 BottomSheet 时,第一个 NestedScrollView 也会滚动:

enter image description here

我的期望:
当我滚动 BottomSheet 时,另一个 NestedScrollView 不应该滚动。

我尝试过的:
我创建了一个自定义 behavior 并重写了 onInterceptTouchEvent,对于属于 BottomSheet 的事件返回 true,并在 BottomSheet 上调用了 dispatchTouchEvent,它可以防止其他 NestedScrollView 滚动,但是 BottomSheet 本身无法滚动,并且 BottomSheet 子项上的单击事件不再起作用。

这是我的布局:

<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
tools:ignore="UnusedAttribute">

<include
    layout="@layout/toolbar"/>

<android.support.v4.widget.NestedScrollView
    android:id="@+id/nested"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginBottom="?actionBarSize"
    android:background="#ff0"
    android:fillViewport="true"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <LinearLayout
        android:id="@+id/ll1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingTop="24dp">

        <Button
            android:id="@+id/button_1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="8dp"
            android:background="@android:color/holo_green_dark"
            android:padding="16dp"
            android:text="Button 1"
            android:textColor="@android:color/white"/>

        <Button
            android:id="@+id/button_2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="8dp"
            android:background="@android:color/holo_blue_light"
            android:padding="16dp"
            android:text="Button 2"
            android:textColor="@android:color/white"/>

        <Button
            android:id="@+id/button_3"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="8dp"
            android:background="@android:color/holo_red_dark"
            android:padding="16dp"
            android:text="Button 3"
            android:textColor="@android:color/white"/>

        <android.support.v4.widget.Space
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"/>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Bottom..."/>

    </LinearLayout>

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


<android.support.v4.widget.NestedScrollView
    android:id="@+id/bottom_sheet"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/holo_orange_light"
    android:clipToPadding="false"
    android:elevation="4dp"
    android:fillViewport="true"
    app:behavior_peekHeight="60dp"
    app:layout_behavior=".Behavior">

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

        <TextView
            android:id="@+id/tv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:clickable="true"
            android:elevation="6dp"
            android:focusable="true"
            android:padding="16dp"
            android:text="@string/ipsum"
            android:textSize="16sp"/>

      <RecyclerView.../>

    </LinearLayout>


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

我的 toolbar.xml 文件:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.AppBarLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/appbar"
    android:layout_width="match_parent"
    android:layout_height="320dp"
    android:fitsSystemWindows="true">

    <android.support.design.widget.CollapsingToolbarLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        app:layout_scrollFlags="scroll|exitUntilCollapsed">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="fitXY"
            android:src="@drawable/lily_lake"
            app:layout_collapseMode="parallax"/>

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?actionBarSize"
            android:layout_gravity="bottom"
            app:layout_collapseMode="pin"/>


    </android.support.design.widget.CollapsingToolbarLayout>

</android.support.design.widget.AppBarLayout>
1个回答

12

更新了更简单的解决方案。

针对您的问题,解决方案可以分为两个部分:

  1. 如何在不滚动应用栏的情况下提高底部工作表?
  2. 如何在提高后降低底部工作表。

要在不影响应用栏的情况下提高底部工作表,我们需要检测底部工作表是否负责滚动,并让应用栏拒绝嵌套滚动,以便它不会接收到后续的嵌套滚动事件。这是通过 AppBarLayout.BehavioronStartNestedScroll 方法实现的。(请参见下面的 MyAppBarBehavior 代码。)

现在我们可以像独立的滑动面板一样向上拖动底部工作表。

enter image description here

现在我们已经将底部表单拖上来了,我们能把它拖回去吗?是和不是。如果底部表单滚动到其内容的顶部,那么如果我们触摸应用栏下方的底部表单,我们就可以将其向下拖动。如果我们在应用栏上方触摸底部表单(当然,这是在底部表单后面),那么我们无法将其向下拖动。这个问题在没有我们修改的基础代码中存在。我认为一个覆盖应用栏的底部表单只是不寻常的。

为了演示这一点,请注意,在此视频中,当拖动底部表单时,应用栏会在其后面打开。

enter image description here

为了改变这种行为,我们将覆盖AppBarLayout.BehavioronInterceptTouchEvent方法,如果正在触摸底部表单,则返回false。
下面是新的AppBarLayout.Behavior: MyAppBarBehavior
class MyAppBarBehavior extends AppBarLayout.Behavior {
    private boolean mIsSheetTouched = false;

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child,
                                       View directTargetChild, View target, int axes, int type) {
        // Set flag if the bottom sheet is responsible for the nested scroll.
        mIsSheetTouched = target.getId() == R.id.bottom_sheet;
        // Only consider starting a nested scroll if the bottom sheet is not touched; otherwise,
        // we will let the other views do the scrolling.
        return !mIsSheetTouched
            && super.onStartNestedScroll(coordinatorLayout, child, directTargetChild,
                                         target, axes, type);
    }

    @Override
    public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
        // Don't accept touch stream here if the bottom sheet is touched. This will permit the
        // bottom sheet to be dragged down without interaction with the appBar. Reset on cancel.
        if (ev.getActionMasked() == MotionEvent.ACTION_CANCEL) {
            mIsSheetTouched = false;
        }
        return !mIsSheetTouched && super.onInterceptTouchEvent(parent, child, ev);
    }
}

我不应该将底部表格标识为特定的id,但这只是一个演示。

将自定义行为添加到应用栏:

<android.support.design.widget.AppBarLayout 
    android:id="@+id/appbar"
    android:layout_width="match_parent"
    android:layout_height="320dp"
    android:fitsSystemWindows="true"
    app:layout_behavior=".MyAppBarBehavior"
    app:expanded="true">

以下是最终结果:

enter image description here

可能有其他实现方式。我会使用现有的滑动面板库,例如AndroidSlidingUpPanel,而不是将底部表单放置在嵌套滚动环境中,然后必须撤消环境的影响。


谢谢回复。我上面提到的代码只是一个示例,实际上,我需要在我的“底部表单”中使用RecyclerView和其他一些View。在这种情况下,ScrollView对我来说不起作用,因为它应该包含RecyclerView - Farshad Tahmasbi
那么,这会是怎么样的呢?您在底部工作表中使用了一个嵌套滚动视图,在其中包含了一个RecyclerView和一些其他非滚动视图。 RecyclerView 何时允许滚动?仅当底部工作表展开时还是其他时间也可以? @ҒάгՏҺαԃ - Cheticamp
1
只有在RecyclerView被扩展时才允许滚动。 - Farshad Tahmasbi
@ҒάгՏҺαԃッ 如果底部表格和其他CoordinatorLayout视图之间没有交互,那么这不就像AndroidSlidingUpPanel一样的滑动面板吗?您是否使用了特定的底部表格功能,例如BottomSheetBehavior.BottomSheetCallback - Cheticamp
我已经将你提到的库作为备选方案考虑了(在我在这里发布问题后),它起作用了,但我很好奇是否有任何方法可以通过BottomSheet消耗滚动并防止将其传递给其他视图。此外,如果我定义RecyclerView的高度为WRAP_CONTENT,那么你在这里建议的方法是可行的解决方案,这种情况下不需要嵌套滚动,对吧? - Farshad Tahmasbi
显示剩余12条评论

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