Android Toolbar + Tab Layout + Drawer, Hide toolbar when scrolling and take TabLayout to the top
Asked Answered
T

10

25

I have activity which has drawer attached to it. Each menu of the drawer is a fragment, and under one of the menu I have a fragment with TabLayout, and each tab contains a RecyclerView. So now, when I scroll the RecyclerView, tab layout is getting hidden but ToolBar remains at the top. What I need is to ToolBar to get hidden(scrollFlags:scroll|enterAlways), and TabLayout should get shown at the top.

So current setup is:

Activity with attached DrawerLayout -> Fragment with TabLayout -> Tab Fragment 1 with RecyclerView -> Tab Fragment 2 with RecyclerView

Taxdeductible answered 30/11, 2015 at 13:29 Comment(4)
did you try to hide(); the toolbar? getSupportedActionbar.hide();Unapproachable
If I go for hiding it manually, then I have to keep track of scroll position which I don't want to do.Taxdeductible
Can you post your layout.xml?Chiquita
why dont you use another activity for tabs and just put CollapsingToolbarLayout...because with same activity it will be hectic for you as you dont want tabs on other fragmentsRosabella
C
14

Less Code More Effective

Hello @Vishal i have found too much for you. because i am also searching this topic before some time.

I have found one brilliant library named MaterialViewPager this is fully customize with what you want to hide in scroll mode.

See the video on https://www.youtube.com/watch?v=r95Tt6AS18c

enter image description here

Costotomy answered 10/12, 2015 at 12:52 Comment(0)
F
9

Can you use the support design library? It has this behavior built in to do exactly what you have described. It uses CoordinatorLayout to accomplish this.

<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:animateLayoutChanges="true"
    >
    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
        <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_scrollFlags="scroll|enterAlways"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
        <android.support.design.widget.TabLayout
            android:id="@+id/tabanim_tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </android.support.design.widget.AppBarLayout>
    <android.support.v4.view.ViewPager
        android:id="@+id/tabanim_viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_alarm_add_white_48dp"
        app:layout_anchor="@id/tabanim_viewpager"
        app:layout_anchorGravity="bottom|right|end"
        android:layout_margin="16dp"
        />

</android.support.design.widget.CoordinatorLayout>
Festschrift answered 8/12, 2015 at 23:5 Comment(0)
G
6

First you need to implement a scroll listener. Here you can find an example HidingScrollListener.

public abstract class HidingScrollListener extends RecyclerView.OnScrollListener {

    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;
    private int previousTotal = 0;
    private boolean loading = true;
    private int visibleThreshold = 4;
    int firstVisibleItem, visibleItemCount, totalItemCount;
    private LinearLayoutManager layoutManager;

    public HidingScrollListener(Context context, LinearLayoutManager layoutManager) {
        mToolbarHeight = Tools.getToolbarHeight(context);
        this.layoutManager = layoutManager;
    }

    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);

        if (newState == RecyclerView.SCROLL_STATE_IDLE) {
            if (mTotalScrolledDistance < mToolbarHeight) {
                setVisible();
            } else {
                if (mControlsVisible) {
                    if (mToolbarOffset > HIDE_THRESHOLD) {
                        setInvisible();
                    } else {
                        setVisible();
                    }
                } else {
                    if ((mToolbarHeight - mToolbarOffset) > SHOW_THRESHOLD) {
                        setVisible();
                    } else {
                        setInvisible();
                    }
                }
            }
        }

    }

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);

        clipToolbarOffset();
        onMoved(mToolbarOffset);

        if ((mToolbarOffset < mToolbarHeight && dy > 0) || (mToolbarOffset > 0 && dy < 0)) {
            mToolbarOffset += dy;
        }
        if (mTotalScrolledDistance < 0) {
            mTotalScrolledDistance = 0;
        } else {
            mTotalScrolledDistance += dy;
        }
        // for load more
        visibleItemCount = recyclerView.getChildCount();
        totalItemCount = layoutManager.getItemCount();
        firstVisibleItem = layoutManager.findFirstVisibleItemPosition();

        if (loading) {
            if (totalItemCount > previousTotal) {
                loading = false;
                previousTotal = totalItemCount;
            }
        }
        if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) {
            // End has been reached
            // Do something

            loading = true;
            onLoadMore();
        }
    }

    private void clipToolbarOffset() {
        if (mToolbarOffset > mToolbarHeight) {
            mToolbarOffset = mToolbarHeight;
        } else if (mToolbarOffset < 0) {
            mToolbarOffset = 0;
        }
    }

    private void setVisible() {
        if (mToolbarOffset > 0) {
            onShow();
            mToolbarOffset = 0;
        }
        mControlsVisible = true;
    }

    private void setInvisible() {
        if (mToolbarOffset < mToolbarHeight) {
            onHide();
            mToolbarOffset = mToolbarHeight;
        }
        mControlsVisible = false;
    }

    public abstract void onMoved(int distance);

    public abstract void onShow();

    public abstract void onHide();

    public abstract void onLoadMore();
}

Than you need to modify your RecyclerView adapter. You need to add an empty view to top of your RecyclerView as high as your your Tolbar.

Here is an example layout for your empty 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="@dimen/abc_action_bar_default_height_material" />

Than you need to override your adapter's getItemViewType and getITemCount methods like below.

@Override
    public int getItemViewType(int position) {
        if (isPositionHeader(position)) {
            return TYPE_HEADER;
        }
        return TYPE_ITEM;
    }

    private boolean isPositionHeader(int position) {
        return position == 0;
    }

    @Override
    public int getItemCount() {
        return mObjects.size() + 1;
    }

Than in adapter's onCreateViewHolder method return a proper layout for your RecyclerView's position likew below:

 @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = null;
        switch (viewType) {
            case TYPE_HEADER:
                view = LayoutInflater.from(mContext).inflate(R.layout.layout_recycler_header, parent, false);
                return new RecyclerHeaderViewHolder(view);

            default:
                view = LayoutInflater.from(mContext).inflate(R.layout.row_recyclerview_category, parent, false);
                return new ViewHolder(view);
        }

    }

And finally add your HidingScrollListener implementation to your RecyclerView like below:

final int mToolbarHeight = Tools.getToolbarHeight(getActivity());
        RecyclerView mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerview);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        mRecyclerView.setLayoutManager(linearLayoutManager);
        mRecyclerView.setAdapter(mAdapter);
        mViewPager.setPadding(mRecyclerView.getPaddingLeft(),
                mToolbarHeight,
                mRecyclerView.getPaddingRight(),
                mRecyclerView.getPaddingBottom());

        mHidingScrollListener = new HidingScrollListener(getActivity(), linearLayoutManager) {
            @Override
            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();
            }

            @Override
            public void onLoadMore() {
            }
        };
        mRecyclerView.setOnScrollListener(mHidingScrollListener);

I hope i understand your problem correctly, and my implementation can help you.

Good luck.

Edit: You can implement LoadMore and PullToRefresh implementation easily to this solution. You can add your api request to loadMore. There's a tricy part in PullToRefresh. After you pull to refresh, clean your data and notify adapter do not to forget set visibleItemCount and totalItemCount to 0 in your hiding scroll implementation. If you do not set to 0, after you refreshed your load more will not work properly. You'll get less data as your item count in your pagination.

Gavial answered 9/12, 2015 at 14:24 Comment(0)
C
2

As far as I know there is nothing build in that does this for you. However you could have a look at the Google IO sourcecode, especially the BaseActivity. Search for "auto hide" or look at onMainContentScrolled

In order to hide the Toolbar your can just do something like this:

toolbar.animate().translationY(-toolbar.getBottom()).setInterpolator(new AccelerateInterpolator()).start();

If you want to show it again you call:

toolbar.animate().translationY(0).setInterpolator(new DecelerateInterpolator()).start();

Found here: android lollipop toolbar: how to hide/show the toolbar while scrolling?

Cryptogam answered 3/12, 2015 at 20:20 Comment(0)
S
2

I had the same architecture in my application, this how i make it :

<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
>

<android.support.design.widget.AppBarLayout
    android:id="@+id/appbar_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

<android.support.v7.widget.Toolbar
    android:id="@+id/main_toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="@color/chat_primary_color"
    app:layout_scrollFlags="scroll|enterAlways"
    android:elevation="4dp"/>

<android.support.design.widget.TabLayout
    android:id="@+id/tab_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?attr/colorPrimary"
    android:elevation="6dp"
    android:minHeight="?attr/actionBarSize"
    android:layout_below="@id/main_toolbar"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
</android.support.design.widget.AppBarLayout>

<android.support.v4.view.ViewPager
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="fill_parent"
    android:layout_below="@id/appbar_layout"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    />
<android.support.v4.widget.NestedScrollView
    android:id="@+id/container_fragment"
    android:layout_width="match_parent"
    android:layout_height="fill_parent"
    android:layout_below="@id/appbar_layout"
    android:fillViewport="true"
    android:foregroundGravity="center"
    app:layout_behavior=".FixedScrollingViewBehavior"
    />

The ViewPager used for the tabs and NestedScrollView used as FrameLayout for the other fragment, i show the ViewPager for the fragments that needs tabs and i hide the NestedScrollView in the other case.

You can find the behavior here for the NestedScrollView FixedScrollingViewBehavior

Swansdown answered 3/12, 2015 at 20:23 Comment(0)
C
2

You can show us your xml code if you want to find your bugs, below is my code share for those who wants to implement Toolbar, Drawer, Tab, and RecycleView in theri application.

https://github.com/Gujarats/Android-Toolbar-Drawer-tab-recyvleview-

Hope it helps

Cristalcristate answered 5/12, 2015 at 16:0 Comment(2)
yes you're right but the author of this question didn't show his xml or code, he just showing the step and got the problem, when scrolling the toolbar and the tab layout, so I for the sake of helping people I share this code as the answer.Cristalcristate
sorry I didn't update the link, there you go, I just updated the link hope it helpsCristalcristate
S
2

You can try the following one, which I have used to hide the toolbar, and make the scrollview take the whole screen for full page reading in my application design.

It is as follows.

  1. Hide the toolbar.
  2. Get your phone screen width and Height.
  3. Store the Tab layout Height and width to a temporary variable.
  4. Assign the phone screen width and Height to your Tab Layout.

This can be done in the following way:

getSupportActionBar().hide();    
int mwidth = getApplicationContext().getResources().getDisplayMetrics().widthPixels;
int mheight = getApplicationContext().getResources().getDisplayMetrics().heightPixels;
temp = (TabLayout) myfrag.getActivity().findViewById(R.id.TabLayout_genesis);
int getwidth = temp.getWidth();
int getheight = temp.getHeight();
temp.setMinimumHeight(mheight);
temp.setMinimumWidth(mwidth);

Hope it helps.

Scratch answered 5/12, 2015 at 17:41 Comment(0)
T
1
Everyone is giving the code, "Talk is cheap, show me the code" right. 
I prefer not showing the code this time. 
I will talk. I do not recommand such a complicated activity.

DrawerLayout and TabLayout are the 2 of major navigation method for android. DrawerLayout and TabLayout shown in a same activity do against the android developement guildline. And if you do so your app will be very hard to use.

Imagine that, if the user do a right-left swipe, should you swipe gesture the pagerview or the drawerlayout? I see you may apply the swipe gesture to the drawerlayout when the user swipe from the right-egde of the activity, otherwise you may apply the gesture to the pagerview, but how do you make sure the user knows this rule?

Even the users know how to swipe your activity (users may very make sense nowadays), your app still look very complicated.

My suggestion is,

 if you have less than 5 main menus, just use tablayout + actionbar, 
 if you have more than 5 main menus, use drawerlayout + actionbar. 
 you don't have to use both navigation in a row, you can still place the important actions to the actionbar right.
Turgor answered 10/12, 2015 at 9:20 Comment(0)
G
0

To hide your Toolbar anytime you can use :

getSupportActionBar().hide();

for more explanation view url1 or url2

Giles answered 10/12, 2015 at 13:2 Comment(0)
C
0

Remove coordinator layout used in tabbed activity. Use LinearLayout

Con answered 9/8, 2018 at 17:47 Comment(1)
Please put this answer in comment sectionSirius

© 2022 - 2024 — McMap. All rights reserved.