21

I am trying to achieve an effect like WhatsApp has, where the Toolbar (when scrolled) will clip into view magnetlike, or out of view magnetlike.

What I have im my MainActivity XML:

  • DrawerLayout - Base Layout
  • CoordinatorLayout - Layout for the Appbar and Toolbar and Tabs
  • AppBarLayout - For holding Toolbar and Tabs
  • Toolbar - has THIS flag: app:layout_scrollFlags="scroll|enterAlways"
  • SlidingTabLayout - Displays tabs
  • ViewPager - For tabs
  • RecyclerView - For coordinatorlayout

Now dont get me wrong, it works, when I scroll down the toolbar gets pushed out of view but say I stop scrolling halfway, then the toolbar just sits there half hidden out of view and the other half in view..

How can I approach solving this problem, as I want it to either snap out of view or into view.

cimmanon
  • 67,211
  • 17
  • 165
  • 171
Linxy
  • 2,525
  • 3
  • 22
  • 37
  • 1
    Same here! I only found this post, but i'm not there yet...https://mzgreen.github.io/2015/06/23/How-to-hideshow-Toolbar-when-list-is-scrolling%28part3%29/ – Entreco Aug 06 '15 at 17:32

3 Answers3

39

This feature has been added in 23.1.0 version of android support library. From release notes:

Added edge snapping support to the AppBarLayout class by adding the SCROLL_FLAG_SNAP constant. When scrolling ends, if the view is only partially visible, the view is snapped and scrolled to its closest edge.

<android.support.design.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <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="wrap_content"
                    app:layout_scrollFlags="scroll|enterAlways|snap" />
           -----
           -----

For more info: http://android-developers.blogspot.in/2015/10/android-support-library-231.html

Floern
  • 33,559
  • 24
  • 104
  • 119
Abhishek V
  • 12,488
  • 6
  • 51
  • 63
7

EDIT: as of support 23.1.0 this is no longer needed. See this answer instead.

One possible way to solve this is customizing the Behavior set to your AppBarLayout.

<android.support.design.widget.AppBarLayout
    app:layout_behavior="com.myapp.AppBarLayoutSnapBehavior"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    ...

Your AppBarLayoutSnapBehavior would change the default behavior of AppBarLayout.Behavior, by adding the snap logic when the scroll stops. Hopefully, the code below is self explanatory.

package com.myapp;

public class AppBarLayoutSnapBehavior extends AppBarLayout.Behavior {

    private ValueAnimator mAnimator;
    private boolean mNestedScrollStarted = false;

    public AppBarLayoutSnapBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child,
                                       View directTargetChild, View target, int nestedScrollAxes) {
        mNestedScrollStarted = super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
        if (mNestedScrollStarted && mAnimator != null) {
            mAnimator.cancel();
        }
        return mNestedScrollStarted;
    }

    @Override
    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target) {
        super.onStopNestedScroll(coordinatorLayout, child, target);

        if (!mNestedScrollStarted) {
            return;
        }

        mNestedScrollStarted = false;

        int scrollRange = child.getTotalScrollRange();
        int topOffset = getTopAndBottomOffset();

        if (topOffset <= -scrollRange || topOffset >= 0) {
            // Already fully visible or fully invisible
            return;
        }

        if (topOffset < -(scrollRange / 2f)) {
            // Snap up (to fully invisible)
            animateOffsetTo(-scrollRange);
        } else {
            // Snap down (to fully visible)
            animateOffsetTo(0);
        }
    }

    private void animateOffsetTo(int offset) {
        if (mAnimator == null) {
            mAnimator = new ValueAnimator();
            mAnimator.setInterpolator(new DecelerateInterpolator());
            mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    setTopAndBottomOffset((int) animation.getAnimatedValue());
                }
            });
        } else {
            mAnimator.cancel();
        }

        mAnimator.setIntValues(getTopAndBottomOffset(), offset);
        mAnimator.start();
    }
}

The only thing is, the scroll view (in my case a RecyclerView) snaps along with the Toolbar. I actually like it this way, but I'm not sure that's what you want.

Community
  • 1
  • 1
tdevaux
  • 1,842
  • 17
  • 14
  • This actually doesn't provide the same exact effect as whatsapp style. Even on simple touch toolbar goes off screen. and on slight drag down actually pulls toolbar down anywhere(scroll position) in recyclerview – Rohit Sep 25 '15 at 08:46
  • 1
    How would you have it so the RecyclerView doesn't snap along with the Toolbar? Your solution is perfect except for that one thing. – StackOverflowMaster Sep 30 '15 at 23:23
0

I just hided action bar layout in main activity and set span for CollapsingToolbarLayout. it works for me.

in main activity

    setSupportActionBar(mToolbar);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);     
    getSupportActionBar().hide();

    CollapsingToolbarLayout collapsingToolbar =
            (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
    collapsingToolbar.setTitle("Name");
    loadBackdrop();

and layout_activity_main

<android.support.design.widget.AppBarLayout
    android:id="@+id/appbar"
    android:layout_width="match_parent"
    android:layout_height="@dimen/detail_backdrop_height"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    android:fitsSystemWindows="true">

    <android.support.design.widget.CollapsingToolbarLayout
        android:id="@+id/collapsing_toolbar"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_scrollFlags="scroll|snap"
        android:fitsSystemWindows="true"
        app:contentScrim="?attr/colorPrimary"
        app:expandedTitleMarginStart="48dp"
        app:expandedTitleMarginEnd="64dp">

        <ImageView
            android:id="@+id/backdrop"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            android:fitsSystemWindows="true"
            app:layout_collapseMode="parallax" />

        <android.support.v7.widget.Toolbar
            android:id="@+id/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>
K.Dᴀᴠɪs
  • 9,945
  • 11
  • 33
  • 43
Zahra.HY
  • 1,684
  • 1
  • 15
  • 25