CoordinatorLayout 行为是否只能应用于 CoordinatorLayout 的直接子项?

Can CoordinatorLayout Behavior be applied only on direct children of CoordinatorLayout?

根据我目前的阅读,Behavior 只能应用于 CoordinatorLayout 的直系子代。但是下面的代码让我感到困惑:

<?xml version="1.0" encoding="utf-8"?>
<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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".ScrollingActivity">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar"
        android:layout_width="match_parent"
        android:layout_height="@dimen/app_bar_height"
        android:fitsSystemWindows="true"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/toolbar_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="@android:color/holo_red_light"
            app:layout_scrollFlags="scroll"
            app:toolbarId="@+id/toolbar">

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="parallax"
                app:popupTheme="@style/AppTheme.PopupOverlay" />

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


    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v4.widget.NestedScrollView
            android:id="@+id/nestedScrollView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            tools:context=".ScrollingActivity"
            tools:showIn="@layout/activity_scrolling">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="@string/large_text" />

        </android.support.v4.widget.NestedScrollView>
    </FrameLayout>
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Test Button"
        android:visibility="visible"
        android:layout_gravity="bottom"
        app:layout_anchor="@id/nestedScrollView"
        app:layout_behavior="am.i.coord.CustomBehavior"
        />

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

NestedScrollView 不是 CoordinatorLayout 的直接子代(包裹在 FrameLayout 中),但仍然应用了 Behavior,这会正确触发 AppBarLayout 的更改。

我在同一级别添加自定义 behaviorButton 仅当我将其设为 CoordinatorLayout 的直接子项时才有效。如果我将它作为 NestedScrollView 的同级移动到 FrameLayout 中,那么将执行 none 个回调。

为什么会有这种差异? 如果 Behavior 不打算被 CoordinatorLayout's 非直接子级使用,是否有另一种方式让非直接子级在 NestedScrollView 中的滚动更改时得到通知? 我只能考虑向 CoordinatorLayout 添加一个虚拟视图,它将向间接子项发出滚动事件,但这会使代码变得混乱。

是的,行为必须附加到 CoordinatorLayout 的直接子级。为什么它适用于 NestedScrollViewIntercepting everything with CoordinatorLayout blog post 中有详细说明:

Nested scrolling can originate not only on direct children of a CoordinatorLayout, but on any child View (a child of a child of a child of a CoordinatorLayout, for example)

这是一个单独的 属性 嵌套滚动本身,而不是 CoordinatorLayout 独有的东西:嵌套滚动事件通过每个父级向上传播视图层次结构 ViewGroup。这就是 CoordinatorLayout 获得对这些事件的访问权限的方式,而行为是允许 CoordinatorLayout 将这些事件分派给不直接在滚动视图的视图层次结构中的其他子项的原因。

如您所料,如果您希望间接子级了解滚动变化,则必须有 CoordinatorLayout 的直接子级,即使它是虚拟视图。当然,您可以创建 CoordinatorLayout 的子类,如果您愿意,可以挂接到相同的事件流中,因为 all of the methods 可以被覆盖。