According to the official documentation, it is a super powered FrameLayout.
It allows the developer to create dependancies among the various view that populate the layout, creating dynamic effects which ultimately result in a more immersive user experience.
Recently, I'm developing an application, which I will post on this blog, and I wanted to experiment with this tool and I ended up creating a custom behavior for my views. Creating behaviors will enable you to, quite literally, do whatever you want with your views in response to other views.
Before I post any code, this is the effect I was trying to achieve:
Let's have a look at the code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | public class PlaceDetailsCardDisapperBehaviour extends CoordinatorLayout.Behavior<CardView> { float maximumDifference = 0; public PlaceDetailsCardDisapperBehaviour(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean layoutDependsOn(CoordinatorLayout parent, CardView child, View dependency) { return dependency instanceof NestedScrollView; } @TargetApi(Build.VERSION_CODES.M) @Override public boolean onDependentViewChanged(CoordinatorLayout parent, CardView child, View dependency) { int targetLoc[] = new int[2]; dependency.getLocationInWindow(targetLoc); int[] childLocation = new int[2]; child.getLocationInWindow(childLocation); float YThreshold = GlobalVariables.DpToPx(100); if(maximumDifference==0) maximumDifference = childLocation[1] - YThreshold; float currentDifference = childLocation[1] - YThreshold; float perc = currentDifference / maximumDifference; if(perc>1.0f) perc = 1.0f; else if(perc<0) perc = 0; child.setScaleX(perc); child.setScaleY(perc); return false; } } |
We create a class that extends CoordinatorLayout.Behavior<CardView>, and we pass in CardView as that is the type of view we are writing the behavior for.
Although we do not call the constructor directly it is important to implement it as it is invoked automatically when the layout is being inflated.
We then override the method layoutDependsOn, which is a method that is called every time something changes in the layout and we must return the class of the view our behavior will react in response to. In our case, the NestedScrollView.
When this method returns true, OnDependentViewChanged is called immediately and this is where we write the reaction. In our case, we simply check the distance of the nested scroll being dragged from the top of the screen, we get a percentage of the current position and set it as size X and Y for our CardView.
In order to apply our behavior to the view we simply need to add a single line in the xml layout file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | <android.support.v7.widget.CardView android:id="@+id/placeDetailsCard" app:layout_behavior="com.blogspot.androidcanteen.interestpoints.PlaceDetailsCardDisapperBehaviour" app:layout_anchor="@+id/appbar" app:layout_anchorGravity="bottom|center" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="20dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingLeft="6dp" android:paddingRight="6dp"> <me.grantland.widget.AutofitTextView android:text="Title" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/theTitle" android:textAppearance="@style/Base.TextAppearance.AppCompat.Large" android:gravity="center_horizontal" android:textStyle="normal|bold" tools:textSize="18sp" android:layout_weight="0.5" android:padding="2dp" /> <me.grantland.widget.AutofitTextView android:text="" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/theType" android:textAppearance="@style/Base.TextAppearance.AppCompat.Small" android:gravity="center_horizontal" android:textStyle="italic" tools:textSize="12sp" android:layout_weight="0.5" android:padding="2dp" /> </LinearLayout> </android.support.v7.widget.CardView> |
The behavior is applied on line 3, directly to the CardView. It is very important to remember that every behavior we write must be applied to a direct child of the Coordinator Layout. For example, this would not work if we applied the custom behavior to the Linear Layout inside the CardView, regardless whether we modify the Java code accordingly.