ZOFTINO.COM android and web dev tutorials

Android Coordinator Layout & Custom Behavior

CoordinatorLayout is provided as part of design support library to enable the implementation of material design guidelines in android applications. Coordinator layout is a frame layout with extra capabilities and features.

The main purpose of coordinator layout is to allow communication between child views. This is achieved by defining Behaviour for child views of coordinator layout.

Behaviour is a plug-in which enables interaction between child views of coordinator layout. It has methods which are called by coordinator layout on certain events such as tap, double taps, drags, swipes, flings and other gestures.

Method layoutDependsOn is called by coordinator layout to find out dependency between two child views and onDependentViewChanged method is called when there is a change in the position or size of dependent view. Coordinator layout calls onInterceptTouchEvent method on motion events.

In the implementation of behavior for a view, you need to return true if the child depends on dependent view passed to layoutDependsOn method. Simply by checking instance type of dependent view or using any other information, it can be figured out whether there is a dependency or not, return true if there is a dependency between child and dependent view passed to layoutDependsOn method.

Then coordinator layout calls onDependentViewChanged method if there is a change in position or size of dependent view, here you can change child view.

Design support library provides behavior implementations for some views such as AppBarLayout, BottomSheet, FloatingActionButton and other.

Creating custom behavior for a view is easy. If the requirement is simple, as explained above, you need to just implement layoutDependsOn and onDependentViewChanged methods.

Coordinator layout with custom behavior for a child view example

I am going to show how to implement custom behavior for text view and list view. In this example, text view and list view are part of coordinator layout and on scrolling the list view, text view and list view positions change. The behavior of view repositioning is provided in Behavior implementations of text view and list view.

In the list view behavior implementation, onInterceptTouchEvent method is used to provide behavior. Coordinator layout calls onInterceptTouchEvent method on occurrence of any motion events. In this example, the movement event we are interested is scrolling.

For test view, layoutDependsOn and onDependentViewChanged methods are used to provide behavior. Coordinator layout calls layoutDependsOn every time there is a change in position of views. In this example, we are interested in list view position change. Our implementation returns true if dependency is listview. Immediately after layoutDependsOn returns true, coordinator layout calls onDependentViewChanged.

Coordinator layout and custom behavior output

android coordinator layout and custom behavior example

Coordinator layout and custom behavior Code

Activity

 package com.zoftino.materialdesign;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;

public class CoordinatorLayoutActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_coordinate_layout);

        TextView tv = (TextView) findViewById(R.id.storeNme);
        tv.setText("Amazon");

        ListView lv =(ListView)this.findViewById(R.id.cpn_list);
        lv.setAdapter(new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, CouponStoreData.arrayOfCoupons));

    }

}
 

Activity layout

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.zoftino.materialdesign.CoordinatorLayoutActivity">

    <android.support.v7.widget.Toolbar
        android:id="@+id/z_toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        android:elevation="4dp"></android.support.v7.widget.Toolbar>
    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/coordinator_layout"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView
            android:text=""
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:textSize="80dp"
            android:textColor="@color/colorAccent"
            android:id="@+id/storeNme"
            app:layout_behavior ="com.zoftino.materialdesign.ZoftinoTextViewBehavior"></TextView>

        <ListView
            android:id="@+id/cpn_list"
            android:layout_marginTop="200dp"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior ="com.zoftino.materialdesign.ZoftinoListViewBehavior"></ListView>


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

TextView behavior

 package com.zoftino.materialdesign;

import android.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;


public class ZoftinoTextViewBehavior extends CoordinatorLayout.Behavior {
    private static final float TEXT_SIZE = 20;

    public ZoftinoTextViewBehavior(){
        super();
    }
    public ZoftinoTextViewBehavior(Context context, AttributeSet attrs){
        super(context, attrs);
    }
    public boolean layoutDependsOn (CoordinatorLayout parent,
                                    View child,
                                    View dependency){
       return dependency instanceof ListView;
    }
    public boolean onDependentViewChanged (CoordinatorLayout parent,
                                           View child,
                                           View dependency){
        if(child instanceof TextView && dependency instanceof  ListView){

            TextView tv = (TextView) child;
            ListView lv = (ListView)dependency;
            int vp =lv.getFirstVisiblePosition();

            if(lv.getFirstVisiblePosition() >= 3){
                tv.setTextSize(20);
            }else if(lv.getFirstVisiblePosition() < 3){
                tv.setTextSize(80);

            }
        }

         return false;
    }
}
 

ListView behavior

 package com.zoftino.materialdesign;

import android.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ListView;

import java.util.List;

public class ZoftinoListViewBehavior extends CoordinatorLayout.Behavior {
    public ZoftinoListViewBehavior(){
        super();
    }
   public ZoftinoListViewBehavior(Context context, AttributeSet attrs){
       super(context, attrs);
   }

    public boolean onInterceptTouchEvent(CoordinatorLayout parent, View child, MotionEvent ev) {

        if(child instanceof ListView && ev.getActionMasked() == MotionEvent.ACTION_DOWN){

            ListView lv = (ListView )child;
            List<View> dependentsLst = parent.getDependents(child);

            int txtTop = dependentsLst.get(0).getTop();
            int top = lv.getTop();

            if(top - txtTop > 450 && lv.getFirstVisiblePosition() >= 3){
                lv.setTop(lv.getTop() - 550);
            }else if(lv.getFirstVisiblePosition() < 3 && top - txtTop < 550){
                lv.setTop(lv.getTop() +  550);
            }

        }
        return false;
    }
}