Skip to main content

Android Collapsing ToolbarLayout Example

Android CollapsingToolbarLayout is a wrapper for Toolbar which implements a collapsing app bar. It is designed to be used as a direct child of a AppBarLayout. CollapsingToolbarLayout is the newly introduced in Lollipop , using which you can create awesome scrolling effect.

The following sample will explain you how to achieve this CollapsingToolbarLayout
Build Gradle
file : build.gradle
dependencies {
    compile 'com.android.support:design:23.0.1'
   compile 'de.hdodenhof:circleimageview:2.2.0'
}
 XML Layout
activity_main.xml
<?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="@color/color_grey_lite"     android:fitsSystemWindows="true">     <android.support.design.widget.AppBarLayout         android:id="@+id/id_app_bar_lay"         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:theme="@style/AppTheme.AppBarOverlay">         <android.support.design.widget.CollapsingToolbarLayout             android:id="@+id/collaps_toolbar_layout"             android:layout_width="match_parent"             android:layout_height="match_parent"             app:layout_scrollFlags="scroll|exitUntilCollapsed">             <LinearLayout                 android:layout_width="match_parent"                 android:layout_height="250dp"                 app:layout_collapseMode="parallax"                 android:orientation="vertical"                 android:gravity="center"                 android:layout_gravity="center"                 android:adjustViewBounds="true"                 android:background="@drawable/orange">                 <de.hdodenhof.circleimageview.CircleImageView                     xmlns:app="http://schemas.android.com/apk/res-auto"                     android:id="@+id/profile_image"                     android:layout_gravity="center"                     android:layout_width="match_parent"                     android:layout_height="96dp"                     android:src="@drawable/app_icon"                     app:civ_border_width="2dp"                     app:civ_border_color="#FFFFFF"/>                 <TextView                     android:layout_width="wrap_content"                     android:layout_height="wrap_content"                     android:textStyle="bold"                     android:textAppearance="@style/TextAppearance.AppCompat.Medium"                     android:textColor="@color/color_black"                     android:text="MrBrown's Android"/>             </LinearLayout>             <android.support.v7.widget.Toolbar                 android:id="@+id/toolbar"                 android:layout_width="match_parent"                 android:layout_height="?attr/actionBarSize"                 android:background="?attr/colorPrimary"                 app:layout_collapseMode="pin"                 app:layout_scrollFlags="scroll|enterAlways"                 app:popupTheme="@style/AppTheme.PopupOverlay" />         </android.support.design.widget.CollapsingToolbarLayout>     </android.support.design.widget.AppBarLayout>     <include layout="@layout/content_main" />     <android.support.design.widget.FloatingActionButton         android:id="@+id/fab"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:layout_gravity="bottom|end"         android:layout_margin="16dp"         app:backgroundTint="@color/colorPrimary"         app:srcCompat="@android:drawable/ic_dialog_map" /> </android.support.design.widget.CoordinatorLayout>
content_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView 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:paddingBottom="@dimen/cardview_margin"
    android:paddingLeft="@dimen/cardview_margin"
    android:paddingRight="@dimen/cardview_margin"
    android:paddingTop="@dimen/cardview_margin"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">
    <FrameLayout
        android:id="@+id/content_main_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <android.support.v7.widget.CardView
                android:id="@+id/id_card_one"
                android:layout_width="match_parent"
                android:layout_height="100dp"
                app:cardCornerRadius="5dp"
                android:layout_marginBottom="10dp"
                app:cardBackgroundColor="@color/color_white">
                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:text="CARD VIEW"
                    android:gravity="center"
                    android:layout_gravity="center"
                    android:textAppearance="@style/TextAppearance.AppCompat.Small"
                    android:textStyle="bold"/>
            </android.support.v7.widget.CardView>

            <android.support.v7.widget.CardView
                android:id="@+id/id_card_two"
                android:layout_below="@+id/id_card_one"
                android:layout_width="match_parent"
                android:layout_height="100dp"
                app:cardCornerRadius="5dp"
                android:layout_marginBottom="10dp"
                app:cardBackgroundColor="@color/color_white">
                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:text="CARD VIEW"
                    android:gravity="center"
                    android:layout_gravity="center"
                    android:textAppearance="@style/TextAppearance.AppCompat.Small"
                    android:textStyle="bold"/>
            </android.support.v7.widget.CardView>
            <android.support.v7.widget.CardView
                android:id="@+id/id_card_three"
                android:layout_below="@+id/id_card_two"
                android:layout_width="match_parent"
                android:layout_height="100dp"
                app:cardCornerRadius="5dp"
                android:layout_marginBottom="10dp"
                android:background="@color/color_white">
                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:text="CARD VIEW"
                    android:gravity="center"
                    android:layout_gravity="center"
                    android:textAppearance="@style/TextAppearance.AppCompat.Small"
                    android:textStyle="bold"/>
            </android.support.v7.widget.CardView>
            <android.support.v7.widget.CardView
                android:id="@+id/id_card_four"
                android:layout_below="@+id/id_card_three"
                android:layout_width="match_parent"
                android:layout_height="100dp"
                app:cardCornerRadius="5dp"
                android:layout_marginBottom="10dp"
                android:background="@color/color_white">
                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:text="CARD VIEW"
                    android:gravity="center"
                    android:layout_gravity="center"
                    android:textAppearance="@style/TextAppearance.AppCompat.Small"
                    android:textStyle="bold"/>
            </android.support.v7.widget.CardView>
            <android.support.v7.widget.CardView
                android:id="@+id/id_card_five"
                android:layout_below="@+id/id_card_four"
                android:layout_width="match_parent"
                android:layout_height="100dp"
                app:cardCornerRadius="5dp"
                android:layout_marginBottom="10dp"
                app:cardBackgroundColor="@color/color_white">
                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:text="CARD VIEW"
                    android:gravity="center"
                    android:layout_gravity="center"
                    android:textAppearance="@style/TextAppearance.AppCompat.Small"
                    android:textStyle="bold"/>
            </android.support.v7.widget.CardView>
        </RelativeLayout>
    </FrameLayout>
</android.support.v4.widget.NestedScrollView>
Let us understand the XML Tags in the above xml layout

1. CoordinatorLayout
A powerful FrameLayout that specifies behavior for child views for various interactions. Allows floating views to be anchored in layout.

2. AppBarLayout
Is essentially a LinearLayout (vertical). It helps respond to its children’s scroll events (scroll gestures). Responsible for implementing many features of material design’s app bar. Depends heavily on being used as a direct child within CoordinatorLayout.

3. CollapsingToolbarLayout
Wrapper for Toolbar that makes the header image collapse into the Toolbar adjusting its title size.What’s left is the ImageView which holds our actual header’s image and Toolbar which we’re familiar with.

4. NestedScrollView
It’s an special scroll view for the smooth scrolling effect, inside this place the desired content . Here in this example will add several Cards as its children.

Flags include :

scroll: this flag should be set for all views that want to scroll off the screen – for views that do not use this flag, they’ll remain pinned to the top of the screen.

enterAlways: this flag ensures that any downward scroll will cause this view to become visible, enabling the ‘quick return’ pattern .

enterAlwaysCollapsed: When your view has declared a minHeight and you use this flag, your View will only enter at its minimum height (i.e., ‘collapsed’), only re-expanding to its full height when the scrolling view has reached it’s top.

exitUntilCollapsed: this flag causes the view to scroll off until it is ‘collapsed’ (its minHeight) before exiting .

Note : all views using the scroll flag must be declared before views that do not use the flag.This ensures that all views exit from the top, leaving the fixed elements behind.

Collapse Mode
  • Parallax scrolling with the ImageView is achieved by simply setting its layout_collapseMode to parallax.
  • The Toolbar must use pin as its collapseMode because we want the Toolbar to persist and remain on top as the user scrolls down.
MainActivity.java

To make the toolbar color transparent on non-collapse

      appBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener() {
    @Override
    public void onStateChanged(AppBarLayout appBarLayout, State state) {

        int toolbarBackground = (state == AppBarStateChangeListener.State.COLLAPSED) ? R.color.colorPrimary : R.color.color_transparent;
        toolbar.setBackgroundColor(ContextCompat.getColor(MainActivity.this, toolbarBackground));
      }
    });

To make actionbar title only on collapse
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
    @Override
    public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
        if (scrollRange == -1) {
            scrollRange = appBarLayout.getTotalScrollRange();
        }
        if (scrollRange + verticalOffset == 0) {
            collapsingToolbarLayout.setTitle(getResources().getString(R.string.app_name));
            isShow = true;
        } else if(isShow) {
            collapsingToolbarLayout.setTitle(" ");
            isShow = false;
        }
    }
});

Complete Java classes
MainActivity.java
public class MainActivity extends AppCompatActivity {
    private AppBarLayout appBarLayout;
    private Toolbar toolbar;
    CollapsingToolbarLayout collapsingToolbarLayout;
    boolean isShow = true;
    int scrollRange = -1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        collapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.collaps_toolbar_layout);
        appBarLayout = (AppBarLayout) findViewById(R.id.id_app_bar_lay);
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        setTitle(getResources().getString(R.string.app_name));
        collapsingToolbarLayout.setTitle(getResources().getString(R.string.app_name));
        collapsingToolbarLayout.setContentScrimColor(getResources().getColor(R.color.color_yellow));
        /*to make the toolbar color transparent on non-collapse*/
        appBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener() {
            @Override
            public void onStateChanged(AppBarLayout appBarLayout, State state) {
                int toolbarBackground = (state == AppBarStateChangeListener.State.COLLAPSED) ? R.color.colorPrimary : R.color.color_transparent;
                toolbar.setBackgroundColor(ContextCompat.getColor(MainActivity.this, toolbarBackground));
            }
        });
        /*to make actionbar title only on collapse*/
        appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
            @Override
            public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
                if (scrollRange == -1) {
                    scrollRange = appBarLayout.getTotalScrollRange();
                }
                if (scrollRange + verticalOffset == 0) {
                    collapsingToolbarLayout.setTitle(getResources().getString(R.string.app_name));
                    isShow = true;
                } else if(isShow) {
                    collapsingToolbarLayout.setTitle(" ");
                    isShow = false;
                }
            }
        });
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.context_menu, menu);
        Drawable icon1 = menu.getItem(0).getIcon(); // change 0 with 1,2 ...
        icon1.mutate();
        icon1.setColorFilter(getResources().getColor(R.color.color_white), PorterDuff.Mode.SRC_IN);
        Drawable icon2 = menu.getItem(1).getIcon();
        icon2.mutate();
        icon2.setColorFilter(getResources().getColor(R.color.color_white), PorterDuff.Mode.SRC_IN);
        return true;
    }
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        //your click functions on actionbar icon here...
        return super.onOptionsItemSelected(item);
    }
}
AppBarStateChangeListener.java
public abstract class AppBarStateChangeListener implements AppBarLayout.OnOffsetChangedListener {
    public enum State {
        EXPANDED,
        COLLAPSED,
        IDLE
    }
    private State mCurrentState = State.IDLE;
    @Override
    public void onOffsetChanged(AppBarLayout appBarLayout, int i) {
        if (i == 0) {
            if (mCurrentState != State.EXPANDED) {
                onStateChanged(appBarLayout, State.EXPANDED);
            }
            mCurrentState = State.EXPANDED;
        } else if (Math.abs(i) >= appBarLayout.getTotalScrollRange()) {
            if (mCurrentState != State.COLLAPSED) {
                onStateChanged(appBarLayout, State.COLLAPSED);
            }
            mCurrentState = State.COLLAPSED;
        } else {
            if (mCurrentState != State.IDLE) {
                onStateChanged(appBarLayout, State.IDLE);
            }
            mCurrentState = State.IDLE;
        }
    }
    public abstract void onStateChanged(AppBarLayout appBarLayout, State state);
}
_________________________________________________________________________________

Happy Coding...



















Comments

Popular posts from this blog

Get Phone Number from Contact List - Android Tutorial

When you create an application to send sms or an application to make calls, getting a destination number from the contacts list is a common task. In this Android tip, I am going to show the code to fetch a number from the contacts list. Now let me tell you how to achieve the goal. First, you need to create an Intent object for the PICK_ACTION action. To open the contacts list, the table that contains the contacts information must be specified as a parameter of the constructor of the Intent class. You can refer to the table using ContactsContract.Contacts.CONTENT_URI. Then call the startActivityForResult () method passing the Intent object and request code to open the contacts list. After a contact is selected from the contacts list, to get the result, you need to override the onActivityResult(int reqCode, int resultCode, Intent data) method of the activity. You can call the getData() method of the data parameter to get the table or uri that contains the selected contact. From the t

Spinner with Search on DropDown - Android Tutorial

If you have more values on Dropdown of Spinner its hard to select the last item by making a long scroll. To overcome this issue Android introduced a component called  AutoCompleteTextView Yes it is!!! Then why Spinner with Search? There may be some requirement even though gave much knowledge about it. There is a simple and good library that helps us to achieve this -  SearchableSpinner Gradle dependencies {     ...     implementation 'com.toptoche.searchablespinner:searchablespinnerlibrary:1.3.1' } Usage Now replace your Normal Android Spinner on XML with the following < com.toptoche.searchablespinnerlibrary.SearchableSpinner     android:id="@+id/id_city"     android:layout_width="match_parent"     android:layout_height="wrap_content"     android:background="@android:color/transparent"     android:padding="5dp" /> ___________________________________________________________

Set Focus on Spinner when select Item on Vertical Scroll - Android Tutorial

We may face an issue on Spinner lies on long vertical scroll, (i.e.) when selected and item from dropdown the focus moves to top of scroll. To avoid this please follow this piece of code spinner.setFocusableInTouchMode( true ); spinner.setOnFocusChangeListener( new View.OnFocusChangeListener() {     @Override     public void onFocusChange(View v, boolean hasFocus) {         if (hasFocus) {             if (spinner.getWindowToken() != null ) {                 spinner.performClick();             }         }     } });   _______________________________________________________________________________ Happy Coding...