Join the social network of Tech Nerds, increase skill rank, get work, manage projects...
 
  • How to hide/show Toolbar when list is scrolling?

    • 0
    • 0
    • 0
    • 0
    • 0
    • 0
    • 0
    • 0
    • 2.97k
    Comment on it

    This tutorial describes how to show effect when list is scrolling up and down. Hiding Toolbar and any other views when list is scrolling down and showing it again when its scrolling up.
    In this tutorial we are using RecyclerView and Tollbar to achieve this effect as we see in Google play. We will add list header on top of the list. To complete this task follow below points.

    1) - First of all we will create a new project in Android studio and add some necessary libraries.

      compile "com.android.support:recyclerview-v7:21.0.0"
      compile 'com.android.support:cardview-v7:21.0.3'
    

    2)- We will define styles.xml so that our app can use Material Theme .

     <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    </style>
    

    3)- Next create a activity_main.xml for our MainActivity class.

        <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
         <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:clipToPadding="false"/>
    
        <LinearLayout
            android:id="@+id/toolbarContainer"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
    
            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"/>
    
          <include layout="@layout/tabs_layout"/>
    
    
        </LinearLayout>
    
        <ImageButton
            android:id="@+id/fabButton"
            android:layout_width="56dp"
            android:layout_height="56dp"
            android:layout_gravity="bottom|right"
            android:layout_marginBottom="16dp"
            android:layout_marginRight="16dp"
            android:visibility="invisible"
            android:background="@drawable/fab_background"
            android:src="@mipmap/ic_favorite_outline_white_24dp"
            />
    </FrameLayout>
    
    • Its very simple layout with RecyclerView, Toolbar and include tab_layout .We put them in a FrameLayout therefore Toolbar needs to be overlayed on RecyclerView. If we don't do this,there will be an empty space above the list when hide the toolbar.

    4) Now create MainActivity class code.

    import android.os.Bundle;
        import android.support.v7.app.ActionBarActivity;
        import android.support.v7.widget.LinearLayoutManager;
        import android.support.v7.widget.RecyclerView;
        import android.support.v7.widget.Toolbar;
        import android.view.animation.AccelerateInterpolator;
        import android.view.animation.DecelerateInterpolator;
        import android.widget.LinearLayout;
    
    import java.util.ArrayList;
    import java.util.List;
    
    
    /**
     * Created by arvindkumar on 5/6/15.
     */
    
    public class MainActivity extends ActionBarActivity {
    
        private LinearLayout mToolbarContainer;
        private int mToolbarHeight;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            setTheme(R.style.AppTheme);
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mToolbarContainer = (LinearLayout) findViewById(R.id.toolbarContainer);
            initToolbar();
            initRecyclerView();
        }
    
        private void initToolbar() {
            Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(mToolbar);
            setTitle(getString(R.string.app_name));
            mToolbar.setTitleTextColor(getResources().getColor(android.R.color.white));
            mToolbarHeight = Utils.getToolbarHeight(this);
        }
    
        private void initRecyclerView() {
            final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
    
            int paddingTop = Utils.getToolbarHeight(MainActivity.this) + Utils.getTabsHeight(MainActivity.this);
            recyclerView.setPadding(recyclerView.getPaddingLeft(), paddingTop, recyclerView.getPaddingRight(), recyclerView.getPaddingBottom());
    
            recyclerView.setLayoutManager(new LinearLayoutManager(this));
            ViewAdapter recyclerAdapter = new ViewAdapter(createItemList());
            recyclerView.setAdapter(recyclerAdapter);
    
            recyclerView.setOnScrollListener(new ListScrollListener(this) {
    
    
                public void onMoved(int distance) {
                    mToolbarContainer.setTranslationY(-distance);
                }
    
                @Override
                public void onShow() {
                    mToolbarContainer.animate().translationY(0).setInterpolator(new DecelerateInterpolator(2)).start();
                }
    
                @Override
                public void onHide() {
                    mToolbarContainer.animate().translationY(-mToolbarHeight).setInterpolator(new AccelerateInterpolator(2)).start();
                }
    
            });
        }
    
        private List<String> createItemList() {
            List<String> itemList = new ArrayList<>();
            for(int i=0;i<20;i++) {
                itemList.add("Item "+i);
            }
            return itemList;
        }
    }
    

    5)- we have to add a recycler_item.xml. layout for our list items .

    <?xml version="1.0" encoding="utf-8"?>
    
    <android.support.v7.widget.CardView
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:card_view="http://schemas.android.com/apk/res-auto"
        android:layou_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_margin="8dp"
        card_view:cardCornerRadius="4dp">
    
        <TextView
            android:id="@+id/itemTextView"
            android:layout_width="match_parent"
            android:layout_height="?attr/listPreferredItemHeight"
            android:gravity="center_vertical"
            android:padding="8dp"
            android:text="djfdksjfdsfj"
            style="@style/Base.TextAppearance.AppCompat.Body2"/>
    </android.support.v7.widget.CardView>
    

    6)- Now we will create a ViewHolder class which hold the view what have defined in recycle_item.xml file.Our list using only text so its very easy.

    import android.support.v7.widget.RecyclerView;
    import android.view.View;
    import android.widget.TextView;
    
    /**
     * Created by arvindkumar on 5/6/15.
     */
    public class RecyclerItemViewHolder  extends RecyclerView.ViewHolder {
        private final TextView mItemTextView;
    
        public RecyclerItemViewHolder(final View parent, TextView itemTextView) {
            super(parent);
            mItemTextView = itemTextView;
        }
    
        public static RecyclerItemViewHolder newInstance(View parent) {
            TextView itemTextView = (TextView) parent.findViewById(R.id.itemTextView);
            return new RecyclerItemViewHolder(parent, itemTextView);
        }
    
        public void setItemText(CharSequence text) {
            mItemTextView.setText(text);
        }
    
    }
    

    7)- We will create a ViewAdapter class ViewAdapter.

    import android.content.Context;
    import android.support.v7.widget.RecyclerView;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    
    import java.util.List;
    
    /**
     * Created by arvindkumar on 5/6/15.
     */
    public class ViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
        //added view types
        private static final int TYPE_HEADER = 2;
        private static final int TYPE_ITEM = 1;
    
        private List<String> mItemList;
    
        public ViewAdapter(List<String> itemList) {
            mItemList = itemList;
        }
    
        //modified creating viewholder, so it creates appropriate holder for a given viewType
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            Context context = parent.getContext();
            if (viewType == TYPE_ITEM) {
    
                final View view = LayoutInflater.from(context).inflate(R.layout.recycler_item, parent, false);
                return RecyclerItemViewHolder.newInstance(view);
    
            } else if (viewType == TYPE_HEADER) {
    
                final View view = LayoutInflater.from(context).inflate(R.layout.recycler_header, parent, false);
                return new RecyclerViewHolder(view);
            }
            throw new RuntimeException("There is no type that matches the type " + viewType + " + make sure your using types    correctly");
        }
    
        //modifed ViewHolder binding so it binds a correct View for the Adapter
        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
            if (!isPositionHeader(position)) {
                RecyclerItemViewHolder holder = (RecyclerItemViewHolder) viewHolder;
                String itemText = mItemList.get(position - 1); // we are taking header in to account so all of our items are correctly positioned
                holder.setItemText(itemText);
            }
        }
    
        //our old getItemCount()
        public int getBasicItemCount() {
            return mItemList == null ? 0 : mItemList.size();
        }
    
        //our new getItemCount() that includes header View
        @Override
        public int getItemCount() {
            return getBasicItemCount() + 1; // header
        }
    
        //added a method that returns viewType for a given position
        @Override
        public int getItemViewType(int position) {
            if (isPositionHeader(position)) {
                return TYPE_HEADER;
            }
            return TYPE_ITEM;
        }
    
        //added a method to check if given position is a header
        private boolean isPositionHeader(int position) {
            return position == 0;
        }
    
    }
    

    8)- Now lets create a layout and ViewHolder for the header view.

    <?xml version="1.0" encoding="utf-8"?>
    <View xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"/>
    

    9)- Create RecyclerHeaderViewHolder class- RecyclerViewHolder

    import android.support.v7.widget.RecyclerView;
    import android.view.View;
    
    /**
     * Created by arvindkumar on 5/6/15.
     */
    public class RecyclerViewHolder extends RecyclerView.ViewHolder {
        public RecyclerViewHolder(View itemView) {
            super(itemView);
        }
    }
    

    10)- Showing/hiding views when list is scrolling.

    To achieve this we will create only one more class- ListScrollListener for RecyclerView.

    import android.content.Context;
    import android.support.v7.widget.LinearLayoutManager;
    import android.support.v7.widget.RecyclerView;
    /**
     * Created by arvindkumar on 5/6/15.
     */
    public abstract class ListScrollListener extends RecyclerView.OnScrollListener {
        private int scrolledDistance = 0;
        private boolean controlsVisible = true;
    
        private static final float HIDE_THRESHOLD = 10;
        private static final float SHOW_THRESHOLD = 70;
    
        private int mToolbarOffset = 0;
        private boolean mControlsVisible = true;
        private int mToolbarHeight;
        private int mTotalScrolledDistance;
    
    
        public ListScrollListener(Context context) {
            mToolbarHeight = Utils.getToolbarHeight(context);
        }
    
    
    
    
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
    
            int firstVisibleItem = ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition();
            //show views if first item is first visible position and views are hidden
            if (firstVisibleItem == 0) {
                if(!controlsVisible) {
                    onShow();
                    controlsVisible = true;
                }
            } else {
                if (scrolledDistance > HIDE_THRESHOLD && controlsVisible) {
                    onHide();
                    controlsVisible = false;
                    scrolledDistance = 0;
                } else if (scrolledDistance < -HIDE_THRESHOLD && !controlsVisible) {
                    onShow();
                    controlsVisible = true;
                    scrolledDistance = 0;
                }
            }
    
            if((controlsVisible && dy>0) || (!controlsVisible && dy<0)) {
                scrolledDistance += dy;
            }
    
            mTotalScrolledDistance += dy;
        }
    
    
        public abstract void onHide();
        public abstract void onShow();
    
    }
    

    11)- Create one more class Utils that return height of toolBar and tabsHeight .

    import android.content.Context;
    import android.content.res.TypedArray;
    
    /**
     * Created by arvindkumar on 5/6/15.
     */
    public class Utils {
        public static int getToolbarHeight(Context context) {
            final TypedArray styledAttributes = context.getTheme().obtainStyledAttributes(
                    new int[]{R.attr.actionBarSize});
            int toolbarHeight = (int) styledAttributes.getDimension(0, 0);
            styledAttributes.recycle();
    
            return toolbarHeight;
        }
    
        public static int getTabsHeight(Context context) {
            return (int) context.getResources().getDimension(R.dimen.tabsHeight);
        }
    
    }
    

    Note- In AndroidManifest.xml file we have defined to MainActivity as launcher Activity

 0 Comment(s)

Sign In
                           OR                           
                           OR                           
Register

Sign up using

                           OR                           
Forgot Password
Fill out the form below and instructions to reset your password will be emailed to you:
Reset Password
Fill out the form below and reset your password: