Sunday, October 30, 2016

The Secrets Of The CoordinatorLayout

CoordinatorLayout 

Android introduced this new layout back a few years ago and it is indeed now a corner stone in android development. Such that when you create a new Basic Activity from the templates in Android Studio , the resulting layout already has a CL tucked in it . 

Basics
In the very heart of software programming , everything is basic . Everything is really easy. CL fills in a very basic problem that was there before. However HOW it did that might get a little tricky . 

The problem that CL eradicated upon its introduction was Coordination between views (please refrain from calling me captain obvious as yet). Previously , each view in an hierarchy operated in oblivion. You might place a crocodile with one of them and they wont move an inch . Well CL exists for this reason (not to insert crocodiles). It would report and communicate between its siblings , so to create a more intuitive experience. All views now can work together to obtain a goal.

Under The Hood 

Supposedly you have two views under CL . 

<CL>
    <A></A>
    <B></B>
</CL>

You have a situation in which you have to perform some changes in A as something happens to B . 

In short the semantics of the above dictate that " A depends on B , and when B changes , we're gonna change A".

The way to establish such a relation is through Behaviors.

CoordinatorLayout.Behavior

This class is used to interact between A and B as stated above. Also once we have wrote the mechanics of interactions ,we are going to place our behavior on the view which would trigger it. Let me explain

We earlier said that when B changes we want to do something in A, but what changes are we talking about ? . Lets assume a drag gesture in B should invoke something in A.

we would create a custom Behavior , that would inherit from CL.Behavior 



public class ChangeTrace extends CoordinatorLayout.Behavior<A>
{
    
    @Override
public boolean layoutDependsOn(CoordinatorLayout parent, A child, View dependency) {
  return dependency instanceof B;
}

public boolean onDependentViewChanged(CoordinatorLayout parent, A child, View dependency) {
  //do whatever you'd like with the child here
}


}


We will provide this behavior to B . By rule , the trigger always gets the behavior. This is how B and A would start their communication. 

Where does AppBarLayout fit into the picture ?

People always assume AppBarLayout (ABL) has something integral to with CL. To be fair to them , ABL does not function out of the CL meaningfully. However ABL is a completely separate beast.  The way it works is a little bit different from the simplistic case I talked about above.

Lets consider another pseudo XML.
<CL>
    <ABL></ABL>
    <RV></RV>

</CL>

While explaining the A and B relations above , I talked about A reacting to B's changes. Here it is kind of reverse. Let me explain . 

ABL has a "Default Behavior" that it is decorated by. You would be able to see like this


@CoordinatorLayout.DefaultBehavior(AppBarLayout.Behavior.class)
public class AppBarLayout extends LinearLayout {

This default behavior works only on ABL and it works by detecting a change in its parent CL ( a scroll or a fling) . The RV on the other hand IS DEPENDANT on the AppBarLayout. This relation is maintained by AppBarLayout.ScrollingViewBehavior which pulls up the dependantview accordingly to how much it has collapsed. Observed this obtained from the ScrollingViewBehavior class


@Overridepublic boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
    // We depend on any AppBarLayouts    return dependency instanceof AppBarLayout;}


ABL is most often than not (as far as I am concerned ALWAYS , but I left some room here in case some developer has cooked something together and shames me for it later) a child in the CL castle . ABL always needs a scrollable sibling so that it can cause ABL's engine to react to it. 

ABL's siblings should be any viewgroup/view which is either implements NestedScrollChild OR is  NestedScrollView. So the latest unwelcome player in the field is this . NestedScrolling . What could this be about ?. Sometimes the fact that solving one puzzle leads to another is crippling to me and makes me want to tear my hair (I am bald ) out . Othertimes though, this is what we all love about coding.

NestedScrollView

You firstly need to understand the motivation behind the existance of NSV. I bet you all are aware of the standard appbar recyclerview combination inside a CL. 
Now carefully tread with me here. 

Supposedly the appbar is expanded hence half of the screen contains the appbar and the other half has the RV. When I begin scrolling what would become of it ? . Would the RV items scroll , or would the appbar start to collapse ? . If you have a knot in your belly , I believe you have stumbled upon another neat mystery of CL. If you are scratching your head do not worry. I will break it down for you . 

When you scroll the RV , we will observe that the contents of RV do not start to scroll until the entire appbar (as per its configuration) has collapsed. Only then does RV start to scroll. 

RV implements an awesome interface called NestedScrollChild where it dispatches its scroll to the parent and waits for further instructions. Only if the CL (which is the NestedScrollParent) gives it a green light , does it proceed with its scrolling . The CL would signal the RV a green , when the appbar has stopped its mojo .

How it all comes together (CL , ABL AND NSV)

1) NSV receives a scroll gesture on it and sends it to the CL (since CL is A NestedScrollParent)
2) CL now invokes all the default behaviors of its children since it has now identified a change in it
3) First up is the ABL . Its behavior dictates it to smoothly animate its children (via scrollflags .. more on that laters)
4) The change in ABL also affects NSV since it has implemented a AppBarLayout.ScrollingViewBehaviour which is dependent on ABL. ABL moves , so does the NSV (and its children).

If you've got any questions feel free to push them up . I plan on getting one feet deeper into Behaviors and the NestedScrollChild/Parent in future if times assists.

Code in Peace.