Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make the Toolbar snap into view or out of view when using Google Design Library?

Tags:

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.

like image 787
Linxy Avatar asked Aug 05 '15 17:08

Linxy


People also ask

How do I use CoordinatorLayout?

By specifying Behaviors for child views of a CoordinatorLayout you can provide many different interactions within a single parent and those views can also interact with one another. View classes can specify a default behavior when used as a child of a CoordinatorLayout by implementing the AttachedBehavior interface.

What is coordinator layout?

Android CoordinatorLayout is a super-powered FrameLayout. It has a lot more to offer than it seems. It has additional level of control over it's child views. It coordinates the animations and transitions of child views with one another.

What is layout_collapseMode?

In addition to pinning a view, you can use app:layout_collapseMode="parallax" (and optionally app:layout_collapseParallaxMultiplier="0.7" to set the parallax multiplier) to implement parallax scrolling (say of a sibling ImageView within the CollapsingToolbarLayout ).


2 Answers

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

like image 65
Abhishek V Avatar answered Oct 07 '22 06:10

Abhishek V


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.

like image 33
tdevaux Avatar answered Oct 07 '22 06:10

tdevaux