android – How to properly hide&show the actionbar using the new design library API?-ThrowExceptions

Exception or error:

Background

Suppose I have these elements in the activity:

  • actionbar (actually a Toolbar)
  • tabs (using TabLayout )
  • ViewPager, with fragments.
  • each fragment has ListVIew/RecyclerView.

I wish to have the same behavior as on many apps, that when scrolling, the action bar will hide or show.

A perfect example for it is how the Play Store scrolling works.

Something like this (but with ListView in the fragments of course) :

enter image description here

The problem

I’ve found the “Android-ObservableScrollView” library which shows how to do it for many types of scrolling views, but it doesn’t handle the case of the new TabLayout usage (plus it has issues), as shown on newer samples, like cheesesquare.

On the new API of the design library (shown on the “cheesesquare” example) , it’s more automatic so you don’t need to create so much boilerplate for handling the scrolling and what to do with it.

Something like that:

<android.support.v4.widget.DrawerLayout

  <android.support.design.widget.CoordinatorLayout>

    <android.support.design.widget.AppBarLayout>

      <android.support.v7.widget.Toolbar
       app:layout_scrollFlags="scroll|enterAlways"/>

      <android.support.design.widget.TabLayout/>

    </android.support.design.widget.AppBarLayout>

    <android.support.v4.view.ViewPager
     app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    <android.support.design.widget.FloatingActionButton/>

  </android.support.design.widget.CoordinatorLayout>

  <android.support.design.widget.NavigationView/>

</android.support.v4.widget.DrawerLayout>

This hirerchy promises that snackbars will be below the FABs, and that the action bar will automatically be animated (shown/hidden) based on the inner RecyclerView of the fragments.

Thing is, this seems to work only with RecyclerView, and not with ListView.

Since they are quite complex, it will be very hard to convert them to RecyclverViews.

The question

What would it take to make the above mechanism work for ListViews too?

Is there a way to do it? If so, how?


EDIT: sadly it seems that Google will not support this behavior for ListView, but only for RecyclerView and NestedScrollView (written about here).

So I’ve tried to use the “Android-ObservableScrollView” library, but it has a lot of scrolling issues, including fling issues.

Now I’ve decided to give Android-ParallaxHeaderViewPager . Can anyone please tell me how to make it work in the current scenario? Is it even possible?


EDIT: I’ve decided to convert to RecyclerView after all.
However, all the samples I’ve tried show an issue: when stopping to scroll, the actionbar (and maybe even the FAB) can stay truncated, as opposed to the play store, where it will get animated to either being hidden/shown.

EDIT: It seems I need to use setExpanded when having IDLE for onScrollStateChanged . question is, how to decide when to expand and when to collapse.

How to solve:

this is a nice workaround, but It’s still very different than what the Play Store shows:

for each fragment, call something like that:

    recyclerView.addOnScrollListener(new OnScrollListener() {
        @Override
        public void onScrollStateChanged(final RecyclerView recyclerView, final int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            ((MainActivity) getActivity()).onScrollStateChanged(recyclerView, newState);
        }

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

for the hosting activity:

public void onScrollStateChanged(final RecyclerView recyclerView, final int newState) {
    switch (newState) {
        case RecyclerView.SCROLL_STATE_IDLE:
            mAppBarLayout.setExpanded(mLastDy <= 0, true);
            mLastDy = 0;
            break;
    }
}

public void onScrolled(final RecyclerView recyclerView, final int dx, final int dy) {
    mLastDy = dy == 0 ? mLastDy : dy;
}

Still, if anyone knows how to make it work well (using either ListView or RecyclerView for the fragments), just like on the Play-Store and other apps, please write it down.

###

New design API are for new components only. If that component is going to support older versions then it must work for older versions.

Related to your issue:
I don’t know, whether you have used the suggested library or not. But it works well here in my case. I know that its a very old library and you must have to use listview with that. You can’t implement recyclerview with that. But as i want to have very flexible and smooth effect, I have try it out and it works very well.

You can also make smooth scroll of toolbar with Listview scrolling and also make paralax effect as you have seen in the example.

See this images for the effect I have implemented for my app.
Mark with red color is my toolbar of the app.

Image when it is expanded:

enter image description here

Image when it is collapsed:

enter image description here

I suggest to try that library for your actionbar related issue, if you do not think to change your listview to recyclerview. But if you want to change your listview to recyclerview then you can use new design API for such effect.

Let me know if I can help you more in this case.

Sincerely,

Shreyash

Updated answer

I assume that you need something like THIS.

If it is what you want, then you should have to refer this library and implement like that.

Please refer, Part1, Part2 and part3 for similar effect.

Let me know if you need anything else.

###

Based on @android developer solution which sometimes expand the app bar when list is fully scrolled I made a small change expanding or collapsing the list depending on the scrolled amount (if it’s bigger than the header height then expand).

mHeaderHeight = getResources().getDimensionPixelSize(R.dimen.appbar_height);

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);
        switch (newState) {
            case RecyclerView.SCROLL_STATE_IDLE:
                mAppBar.setExpanded(mScrolledAmount < mHeaderHeight , true);
                break;
        }
    }

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

EDIT: What works even better for me is having different thresholds to expand and collapse

     switch (newState) {
            case RecyclerView.SCROLL_STATE_IDLE:
                if (mScrolledAmount < 50){
                    mAppBar.setExpanded(true , true);
                }
                if (mScrolledAmount > mHeaderHeight) {
                    mAppBar.setExpanded(false, true);
                }
                break;
        }

Leave a Reply

Your email address will not be published. Required fields are marked *