AppbarLayout , CollapsingToolbarLayout and CoordinatorLayout .ViewGroup is to coordinate the view elements that are inside it.
View depend on others. (we will talk about it later).CoordinatorLayout : <?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:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/background_light" android:fitsSystemWindows="true" > <android.support.design.widget.AppBarLayout android:id="@+id/main.appbar" android:layout_width="match_parent" android:layout_height="300dp" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:fitsSystemWindows="true" > <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/main.collapsing" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_scrollFlags="scroll|exitUntilCollapsed" android:fitsSystemWindows="true" app:contentScrim="?attr/colorPrimary" app:expandedTitleMarginStart="48dp" app:expandedTitleMarginEnd="64dp" > <ImageView android:id="@+id/main.backdrop" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:fitsSystemWindows="true" android:src="@drawable/material_flat" app:layout_collapseMode="parallax" /> <android.support.v7.widget.Toolbar android:id="@+id/main.toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" app:layout_collapseMode="pin" /> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <android.support.v4.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="20sp" android:lineSpacingExtra="8dp" android:text="@string/lorem" android:padding="@dimen/activity_horizontal_margin" /> </android.support.v4.widget.NestedScrollView> <android.support.design.widget.FloatingActionButton android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_margin="@dimen/activity_horizontal_margin" android:src="@drawable/ic_comment_24dp" app:layout_anchor="@id/main.appbar" app:layout_anchorGravity="bottom|right|end" /> </android.support.design.widget.CoordinatorLayout> CoordinatorLayout has only three children: AppbarLayout , a scrollable view and an assigned FloatingActionBar . <CoordinatorLayout> <AppbarLayout/> <scrollableView/> <FloatingActionButton/> </CoordinatorLayout> AppBarLayout is LinearLayout on steroids, their elements are placed vertically, with certain parameters the elements can control their behavior when the content is scrolled.
AppBarLayout is a blue view, placed under the vanishing image, it contains a Toolbar , LinearLayout with a title and subtitle and TabLayout with several tabs.AppbarLayout elements using the parameters: layout_scrollFlags . Value: scroll in this case is present in almost all view elements, if this parameter were not specified in any of the AppbarLayout elements, it would remain unchanged, allowing scrollable content to pass behind it.snap , we avoid falling into a semi-animated state , which means that the animation always hides or displays the full view size.LinearLayout which contains the title and subtitle will always be displayed when scrolling up ( enterAlways value), and TabLayout will always be visible because no flag is set to it.AppbarLayout is determined by properly controlling its scroll flags in certain views. <AppBarLayout> <CollapsingToolbarLayout app:layout_scrollFlags="scroll|snap" /> <Toolbar app:layout_scrollFlags="scroll|snap" /> <LinearLayout android:id="+id/title_container" app:layout_scrollFlags="scroll|enterAlways" /> <TabLayout /> <!-- no flags --> </AppBarLayout> SCROLL_FLAG_ENTER_ALWAYS : When using the flag, the view will scroll down regardless of the other scrollable view.SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED : Additional flag for 'enterAlways', which changes the returned view to the initially scrollable, when the height disappears.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED : When exiting, the view will be scrolled until it disappears.SCROLL_FLAG_SCROLL : The view element will scroll in the direction of the scroll event.SCROLL_FLAG_SNAP : At the end of the scroll, if the view is only partially visible, it will be docked to its nearest edge.
FloatingActionButton , since Android Studio v1.2 includes a java decompiler, using ctrl/cmd + click we can check the source code and see what happens: /* * Copyright (C) 2015 The Android Open Source Project * * Floating action buttons are used for a * special type of promoted action. * They are distinguished by a circled icon * floating above the UI and have special motion behaviors * related to morphing, launching, and the transferring anchor point. * * blah.. blah.. */ @CoordinatorLayout.DefaultBehavior( FloatingActionButton.Behavior.class) public class FloatingActionButton extends ImageButton { ... public static class Behavior extends CoordinatorLayout.Behavior<FloatingActionButton> { private boolean updateFabVisibility( CoordinatorLayout parent, AppBarLayout appBarLayout, FloatingActionButton child { if (a long condition) { // If the anchor's bottom is below the seam, // we'll animate our FAB out child.hide(); } else { // Else, we'll animate our FAB back in child.show(); } } } ... } Behavior . In this case CoordinatorLayout.Behavior<FloatingAcctionButton> Which depends on some factors including scrolling, showing FAB or not, I wonder, isn't it?SwipeDismissBehavior . With this new Behavior we can very easily implement the swipe function to cancel in our templates with CoordinatorLayout :
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_swipe_behavior); mCardView = (CardView) findViewById(R.id.swype_card); final SwipeDismissBehavior<CardView> swipe = new SwipeDismissBehavior(); swipe.setSwipeDirection( SwipeDismissBehavior.SWIPE_DIRECTION_ANY); swipe.setListener( new SwipeDismissBehavior.OnDismissListener() { @Override public void onDismiss(View view) { Toast.makeText(SwipeBehaviorExampleActivity.this, "Card swiped !!", Toast.LENGTH_SHORT).show(); } @Override public void onDragStateChanged(int state) {} }); LayoutParams coordinatorParams = (LayoutParams) mCardView.getLayoutParams(); coordinatorParams.setBehavior(swipe); } 

CoordinatorLayout.Behavior<T> , the value of T will be the class that belongs to the view that we need to coordinate, in this case the ImageView , after which we have to override the following methods:layoutDependsOn will be called every time something happens in the layout to return true , once we have defined dependency, in the example, this method works automatically when scrolling (since the Toolbar will move), so we can submit sign to our child to respond accordingly. @Override public boolean layoutDependsOn( CoordinatorLayout parent, CircleImageView, child, View dependency) { return dependency instanceof Toolbar; } layoutDependsOn returns true second onDependentViewChanged will be called. It is here that we must implement our animation, translation or movement always depend on the provided dependency. public boolean onDependentViewChanged( CoordinatorLayout parent, CircleImageView avatar, View dependency) { modifyAvatarDependingDependencyState(avatar, dependency); } private void modifyAvatarDependingDependencyState( CircleImageView avatar, View dependency) { // avatar.setY(dependency.getY()); // avatar.setBlahBlat(dependency.blah / blah); } public static class AvatarImageBehavior extends CoordinatorLayout.Behavior<CircleImageView> { @Override public boolean layoutDependsOn( CoordinatorLayout parent, CircleImageView, child, View dependency) { return dependency instanceof Toolbar; } public boolean onDependentViewChanged( CoordinatorLayout parent, CircleImageView avatar, View dependency) { modifyAvatarDependingDependencyState(avatar, dependency); } private void modifyAvatarDependingDependencyState( CircleImageView avatar, View dependency) { // avatar.setY(dependency.getY()); // avatar.setBlahBlah(dependency.blah / blah); } } Source: https://habr.com/ru/post/270121/
All Articles