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:
app:layout_scrollFlags="scroll|enterAlways"
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.
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.
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.
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 ).
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With