防止Bottom Sheet祖先视图中的滚动

Far*_*sbi 7 android android-layout android-coordinatorlayout android-nestedscrollview bottom-sheet

我有一个CoordinatorLayout包含两个NestedScrollViews,一个有ScrollingViewBehavior,另一个有BottomSheetBehavior和扮演BottomSheet角色,问题是当我拖动时BottomSheet,第一个NestedScrollView滚动:

在此输入图像描述

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

我试了一下:
我创建了一个自定义的行为和覆盖onInterceptTouchEvent,在事件属于BottomSheet返回true和调用dispatchTouchEventBottomSheet,该功能可以防止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>
Run Code Online (Sandbox Code Playgroud)

和我的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>
Run Code Online (Sandbox Code Playgroud)

Che*_*amp 7

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

您的问题的解决方案可分为两个部分:

  1. 如何在不滚动appbar的情况下提升底部工作表?
  2. 一旦抬起,如何降低底部板材.

要在不影响appbar的情况下提升底部工作表,我们需要检测底部工作表何时负责滚动并让appbar拒绝嵌套滚动,以便它不会接收后续嵌套滚动事件.这是通过以下onStartNestedScroll方法实现的AppBarLayout.Behavior.(见MyAppBarBehavior下面的代码.)

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

在此输入图像描述

现在我们已经拖了底板,我们可以把它拖回来吗?是的,不.如果底部工作表滚动到其内容的顶部,那么如果我们触摸appbar 下方的底部工作表,我们可以向下拖动底部工作表.如果我们触摸appbar上的底部纸张(当然,它位于底部纸张后面),那么我们就无法将底部纸张向下拖动.未经我们修改,此问题存在于基础代码中.我认为底页覆盖appbar是不寻常的.

为了演示此通知,在此视频中,当拖动底部工作表时,appbar会在底部工作表后面打开.

在此输入图像描述

要改变这种行为,我们将覆盖onInterceptTouchEventAppBarLayout.Behavior,如果底片被触摸返回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);
    }
}
Run Code Online (Sandbox Code Playgroud)

(我不应该用特定的方法确定底页id,但这只是一个演示.)

将自定义行为添加到appbar:

<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">
Run Code Online (Sandbox Code Playgroud)

这是最终结果:

在此输入图像描述

可能还有其他方法可以实现这一目标.我可能会使用现有的滑动面板库(如AndroidSlidingUpPanel),而不是将底部工作表放在嵌套的滚动环境中,然后我们必须撤消环境的影响.