Android CoordinatorLayout.Behavior
July 07, 2023
On this page we will learn to use CoordinatorLayout.Behavior
in our Android application.
1. The
CoordinatorLayout
is a super-powered FrameLayout
. The CoordinatorLayout
is used for following purpose.
a. As a top-level application decor or chrome layout.
b. As a container for a specific interaction with one or more child views.
2. The
CoordinatorLayout.Behavior
is interaction behavior plugin for child views of CoordinatorLayout
. The interaction can be drags, swipes, flings, or any other gestures.
3. Find the constructor of
CoordinatorLayout.Behavior
.
Behavior() Behavior(Context context, AttributeSet attrs)
CoordinatorLayout.Behavior
that are overridden to change the behaviour of child views.
layoutDependsOn() onApplyWindowInsets() onAttachedToLayoutParams() onDependentViewChanged() onDependentViewRemoved() onDetachedFromLayoutParams() onInterceptTouchEvent() onLayoutChild() onNestedPreScroll()
Custom Behavior for FloatingActionButton
In our demo application, we have aFloatingActionButton
and we will change its behavior on the opening of Snackbar
. We will open Snackbar
on the click of options menu item. The Snackbar
layout overlaps FloatingActionButton
. Using CoordinatorLayout.Behavior
we will hide the button until Snackbar
layout stays open.
Find the custom behavior code.
CustomFabVisibilityBehavior.java
package com.cp.myapplication; import android.content.Context; import android.util.AttributeSet; import android.view.View; import androidx.annotation.NonNull; import androidx.coordinatorlayout.widget.CoordinatorLayout; import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.snackbar.Snackbar; import java.util.List; public class CustomFabVisibilityBehavior extends CoordinatorLayout.Behavior { public CustomFabVisibilityBehavior(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean layoutDependsOn(@NonNull CoordinatorLayout parent, @NonNull View child, @NonNull View dependency) { return dependency instanceof Snackbar.SnackbarLayout; } @Override public boolean onDependentViewChanged(@NonNull CoordinatorLayout parent, @NonNull View child, @NonNull View dependency) { boolean snackbarAvail = isSnackbarAvailable(parent, (FloatingActionButton) child); if (snackbarAvail) { child.setVisibility(View.GONE); } else { child.setVisibility(View.VISIBLE); } return false; } private boolean isSnackbarAvailable(CoordinatorLayout parent, FloatingActionButton fab) { final List dependencies = parent.getDependencies(fab); for (int i = 0; i < dependencies.size(); i++) { final View view = (View) dependencies.get(i); if (view instanceof Snackbar.SnackbarLayout && parent.doViewsOverlap(fab, view)) { return true; } } return false; } }
CoordinatorLayout.Behavior
class.
1. layoutDependsOn() :
public boolean layoutDependsOn( @NonNull CoordinatorLayout parent, @NonNull V child, @NonNull View dependency )
layoutDependsOn()
determines whether the supplied child view has another specific sibling view as a layout dependency. This method is called at least once in response to layout request. If this method returns true for a given child and dependency view pair, then
a. The parent
CoordinatorLayout
will always lay out this child after the dependent child is laid out, regardless of child order.
b. The parent
CoordinatorLayout
will call onDependentViewChanged()
when the dependency view's layout or position changes.
2. onDependentViewChanged() :
public boolean onDependentViewChanged( @NonNull CoordinatorLayout parent, @NonNull V child, @NonNull View dependency )
onDependentViewChanged()
responds to a change in a child's dependent view. This method is called whenever a dependent view changes in size or position outside of the standard layout flow.
XML for Layout
The custom behavior class is attached to child views usingapp:layout_behavior
attribute.
res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.coordinatorlayout.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=".MainActivity"> <com.google.android.material.appbar.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/material_on_surface_stroke" android:fitsSystemWindows="true"> <com.google.android.material.appbar.MaterialToolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" /> </com.google.android.material.appbar.AppBarLayout> <androidx.recyclerview.widget.RecyclerView android:id="@+id/rv" android:layout_width="match_parent" android:layout_height="match_parent" /> <com.google.android.material.floatingactionbutton.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="30dp" app:layout_anchor="@id/rv" app:layout_anchorGravity="bottom|center" app:layout_behavior=".CustomFabVisibilityBehavior" app:srcCompat="@android:drawable/ic_dialog_email" /> </androidx.coordinatorlayout.widget.CoordinatorLayout>
FloatingActionButton
is gone. Once the Snackbar disappears, FloatingActionButton
becomes visible.