Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Coordinator layout custom layout behavior never getting called

Firstly, I'd like to preface this with my lack of knowledge about the coordinator layout. I'm merely following tutorials I found online and am curious why my behavior isn't working.

Does the child view inside of coordinator layout have to be app bar layout? Or are you able to put any view inside there.

Also, when I define the res-auto namespace it doesn't give me the option for layout_behavior. Usually android studio will auto-complete if a function is available and it didn't. Although, if I type out layout_behavior it doesn't complain. So maybe it's working...?

Regardless, I've defined my own custom layout behavior and am trying to apply it but it doesn't seem to be working. Any insight would be greatly appreciated.

Here is the layout. I'm trying to apply my custom behavior to the first LinearLayout (search_polls_toolbar) and have it scroll up when the vertical recyclerview scrolls up. (Like the toolbar currently does.) I should also mention, this xml is for a fragment in a viewpager. And the hosting activity has a coordinator layout attached to it that does make the toolbar scroll up. (Could it be conflicted because of that?)

<?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"/>

And here's the custom behavior:

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;
    }
}

And here's the hosting activies' layout.

    <?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>

If anyone would like me to post anymore of my code, please let me know! Thanks :)

like image 307
cj1098 Avatar asked Jul 30 '15 23:07

cj1098


2 Answers

The reason why it is not working is that view with Behavior must be a direct child of CoordinatorLayout. In your case, the hierarchy is: CoordinatorLayout -> RelativeLayout -> LinearLayout (with Behavior).

like image 62
Dmitry Zaytsev Avatar answered Nov 16 '22 02:11

Dmitry Zaytsev


I have a layout such as this. There are a few things located in the upper regions, but the bottom contains only a FAB which is deeply nested.

<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>

The FAB is deeply nested.

CoordinatorLayout > ConstraintLayout > RelativeLayout > FABProgressCircle > FAB

However the RelativeLayout needs to be pushed up by the CoordinatorLayout when the Snackbar is shown.

The behavior which will do this is as simple as follows.

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;
    }
}

Show the Snackbar like this.

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

onDependentViewRemoved needs to be overridden, because when manually dismissing a Snackbar the CoordinatorLayout won't trigger moving the translated View (the FloatingActionButton and its RelativeLayout) back to it's original place. Overriding the method we can translate it back to where it was.

like image 36
Kohányi Róbert Avatar answered Nov 16 '22 02:11

Kohányi Róbert