Coordinator layout custom layout behavior never getting called
Solution 1
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
).
Solution 2
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.
Related videos on Youtube
Comments
-
cj1098 over 1 year
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 :)
-
Konstantin Konopko about 8 yearsSometimes Google makes me cry
-
Ibrahim Disouki over 7 yearsHi, do you know any workaround to solve this problem ?
-
Blablablabli almost 7 yearsWorks perfectly, you just saved my day :D
-
Kohányi Róbert almost 7 years@Blablablabli I've updated my Java code snippet, you might be interested in the change.
-
Blablablabli almost 7 yearsIndeed, I did not know this case had to be handled, you're the MVP :)
-
Kohányi Róbert almost 7 years@Blablablabli Haha, thanks man. One thing bothers me tho'. If the Snackbar is automatically dismissed (that is the user doesn't swipe it away) the "slide down" animation is fluent, smooth and there's no delay. However if I use the "onDependentViewRemoved" fix I mentioned then the "animation" is rigid and there is a delay between the Snackbars removal and the actual start of the FAB's movement. Let me know if you can figure out a fix for the latter. The "rigid" animation, or lack of it can be fixed by applying an animation by using
view.animator()
. -
rgv almost 7 yearsPoint very well explained!