协调布局自定义布局行为从未被调用

25

首先,我要说明一下我对CoordinatorLayout的了解不足。我只是按照我在网上找到的教程进行操作,并且很好奇为什么我的行为不能正常工作。

在CoordinatorLayout中的子视图是否必须是AppBarLayout?还是可以放置任何视图?

此外,当我定义res-auto命名空间时,它没有给我提供layout_behavior选项。通常情况下,如果函数可用,Android Studio会自动完成,但这次没出现。尽管如此,如果我手动输入layout_behavior,它并没有提示错误。所以也许它是有效的……?

不管怎样,我已经定义了自己的自定义布局行为,并试图应用它,但似乎没有起作用。任何见解都将不胜感激。

以下是布局文件。我正在尝试将我的自定义行为应用于第一个LinearLayout(search_polls_toolbar),并在垂直RecyclerView向上滚动时使其向上滚动。(就像工具栏目前正在做的那样。)我还应该提到,这个xml是片段在一个ViewPager中使用的。主持活动有一个附加到它的协调器布局,使得工具栏可以滚动上去。(因此会有冲突吗?)

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    android:id="@+id/root"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
<RelativeLayout
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >
    <LinearLayout
        android:id="@+id/search_polls_toolbar"
        android:layout_width="match_parent"
        android:layout_height="?android:actionBarSize"
        android:background="@color/icitizen_toolbar_orange"
        android:weightSum="1"
      app:layout_behavior="com.example.chrisjohnson.icitizenv2.CustomBehaviors.ToolbarBehavior"
        >

        <EditText
            android:id="@+id/search_polls"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:hint="@string/search_polls"
            android:gravity="center_horizontal"
            android:layout_weight=".5"
            android:drawableLeft="@drawable/magnifying_glass"
            android:drawableStart="@drawable/magnifying_glass"
            android:layout_marginTop="5dp"
            android:layout_marginLeft="15dp"
            android:drawablePadding="-50dp"
            android:paddingLeft="5dp"
            android:paddingTop="5dp"
            android:paddingBottom="10dp"
            android:cursorVisible="false"
            android:textSize="20sp"
            android:background="@color/icitizen_light_orange"
            />

    </LinearLayout>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/poll_horizontal_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="75dp"
        android:layout_below="@id/search_polls_toolbar"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="5dp"
        android:scrollbars="none"
        >

    </android.support.v7.widget.RecyclerView>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/poll_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="10dp"
        android:layout_below="@id/poll_horizontal_recycler_view"
        app:layout_scrollFlags="scroll|enterAlways"
        android:scrollbars="vertical" />

</RelativeLayout>

<android.support.design.widget.FloatingActionButton
    android:id="@+id/polls_fab"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/white_plus_icon"
    android:layout_marginBottom="70dp"
    app:backgroundTint="@color/icitizen_orange"
    app:layout_anchor="@id/container"
    app:layout_anchorGravity="bottom|right|end"
    app:borderWidth="0dp"
    android:layout_marginRight="15dp"
    android:layout_marginEnd="15dp"/>

这里是自定义行为:

public class ToolbarBehavior extends CoordinatorLayout.Behavior<Toolbar> {
    public ToolbarBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
        Toast.makeText(context, "AJSJA", Toast.LENGTH_LONG).show();
    }

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, Toolbar child, View dependency) {
        return dependency instanceof RecyclerView;
    }

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, Toolbar child, View dependency) {
        child.setTranslationY(child.getY());
        return true;
    }
}

这里是托管活动的布局。

    <?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"
    android:id="@+id/coordinatorLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <android.support.design.widget.AppBarLayout
        android:id="@+id/appBarLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?android:attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways"
            />
    </android.support.design.widget.AppBarLayout>
    <android.support.v4.view.ViewPager
        android:id="@+id/home_viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        />
</android.support.design.widget.CoordinatorLayout>

如果有人想让我发布更多的代码,请告诉我!谢谢:)

2个回答

76

无法正常工作的原因是带有Behavior的视图必须是CoordinatorLayout的直接子级。在您的情况下,层次结构为:CoordinatorLayout -> RelativeLayout -> 带有BehaviorLinearLayout


78
有时候谷歌让我哭泣。 - Konstantin Konopko
3
你好,你知道解决这个问题的任何变通方法吗? - Ibrahim Disouki
1
讲解得非常清楚! - rgv

3
我有一个这样的布局。一些东西位于上部区域,但底部只包含一个深度嵌套的FAB。
<android.support.design.widget.CoordinatorLayout
    android:id="@+id/your_coordinator_id">

    <android.support.constraint.ConstraintLayout
        app:layout_behavior="com.yourpackage.YourBehavior">

        <ScrollView>
            ...
        </ScrollView>

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

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

        <!--
            Everything "around" the FAB needs to be moved.
        -->
        <RelativeLayout
            android:id="@+id/your_view_id">

           <com.github.jorgecastilloprz.FABProgressCircle>

                <!--
                   This is the actual FAB.
                -->
                <android.support.design.widget.FloatingActionButton/>
            </com.github.jorgecastilloprz.FABProgressCircle>
        </RelativeLayout>
    </android.support.constraint.ConstraintLayout>
</android.support.design.widget.CoordinatorLayout>

FAB嵌套层次很深。

CoordinatorLayout > ConstraintLayout > RelativeLayout > FABProgressCircle > FAB

然而,当显示Snackbar时,RelativeLayout需要被CoordinatorLayout向上推。

实现此功能的行为非常简单,如下所示。

package com.yourpackage;

...

public class YourBehavior extends CoordinatorLayout.Behavior<ConstraintLayout> {

    public YourBehavior(Context context, AttributeSet attrs) {
    }

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, ConstraintLayout child, View dependency) {
        float translationY = Math.min(0, dependency.getTranslationY() - dependency.getHeight());
        // Note that the RelativeLayout gets translated.
        child.findViewById(R.id.your_view_id).setTranslationY(translationY);
        return true;
    }

    @Override
    public void onDependentViewRemoved(CoordinatorLayout parent, ConstraintLayout child, View dependency) {
        child.findViewById(R.id.your_view_id).setTranslationY(0.0f);
    }

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, ConstraintLayout child, View dependency) {
        return dependency instanceof Snackbar.SnackbarLayout;
    }
}

像这样显示 Snackbar

Snackbar.make(findViewById(R.id.your_coordinator_id), "Message", Snackbar.LENGTH_SHORT).show();

onDependentViewRemoved需要被重写,因为当手动关闭Snackbar时,CoordinatorLayout不会触发将已翻译的View(即FloatingActionButton和其RelativeLayout)移回其原始位置。通过重写该方法,我们可以将其翻译回原来的位置。


完美运行,你救了我的一天:D - Blablablabli
1
@Blablablabli 我更新了我的Java代码片段,你可能会对这个变化感兴趣。 - Kohányi Róbert
的确,我不知道这种情况需要处理,你是MVP :) - Blablablabli
@Blablablabli 哈哈,谢谢你。有一件事情让我困扰。如果 Snackbar 被自动关闭(也就是用户没有滑动它),那么“向下滑动”的动画会很流畅,没有延迟。但是,如果我使用我提到的“onDependentViewRemoved”修复方法,那么“动画”就会变得僵硬,并且在 Snackbar 移除后和 FAB 实际移动开始之间会有延迟。如果你能找到解决后者问题的方法,请告诉我。可以通过使用 view.animator() 应用动画来解决“僵硬”的动画或缺少动画的问题。 - Kohányi Róbert

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