How to detect nested throws stopped in CoordinatorLayout.Behavior?

How to determine if a nested trip is completely stopped using CoordinatorLayout.Behavior? There is no api that can give me a callback when the recycler view is completely stopped.

+5
source share
2 answers

I started this rabbit hole, trying to hide the floating action button (FAB) when the RecyclerView scrolls. The correct way to do this according to several sources is to extend FloatingActionButton.Behavior , override the onStartNestedScroll and onStopNestedScroll and bind your behavior to FAB, for example app:layout_behavior="com.justingarrick.ui.ScrollAwareFabBehavior" . This works for normal (slow) scroll events, but onStopNestedScroll not called when the reset ends.

There are currently several open issues with behavioral change and scrolling; The workaround for me was to implement the OnScrollListener for my RecyclerView and just change the state of the FAB programmatically, for example.

 public class MyFragment extends Fragment { @Bind(R.id.account_list) RecyclerView recyclerView; @Bind(R.id.button_fab) FloatingActionButton fab; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_accounts, container, false); ButterKnife.bind(this, view); recyclerView.setLayoutManager(layoutManager); recyclerView.setAdapter(adapter); recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (newState == RecyclerView.SCROLL_STATE_DRAGGING) fab.hide(); // or hideFab(), see below else if (newState == RecyclerView.SCROLL_STATE_IDLE) fab.show(); // or showFab(), see below } }); return view; } } 

UPDATE This works correctly 99% of the time, but if you use the show() and hide() methods from version 22.2.1 of the design library, you will run into problems when you try to scroll up at the top of your RecyclerView or down at the bottom of your RecyclerView, because viewing The recycler switches states from RecyclerView.SCROLL_STATE_DRAGGING to RecyclerView.SCROLL_STATE_IDLE so fast that it creates a race condition in FloatingActionButtonHoneycombMr1#show() . Thus, to fix this (sigh), you either need to switch to setVisibility() calls if you don't need animations, or re-implement animations without a race condition, for example.

 private void hideFab() { fab.animate().scaleX(0.0F).scaleY(0.0F).alpha(0.0F).setDuration(200L).setInterpolator(new FastOutSlowInInterpolator()).setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { fab.setVisibility(View.GONE); } }); } private void showFab() { fab.animate().scaleX(1.0F).scaleY(1.0F).alpha(1.0F).setDuration(200L).setInterpolator(new FastOutSlowInInterpolator()).setListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { fab.setVisibility(View.VISIBLE); } }); } 
+6
source

I use ScrollerCompat with the ScrollerCompat.fling (..) method to handle intermediate scroll states. So I know when the scroll ends.

 @Override public boolean onNestedFling(final CoordinatorLayout coordinatorLayout, final AppBarLayout child, final View target, final float velocityX, final float velocityY, final boolean consumed) { final int scrollY = target.getScrollY(); final double distance = mFlingHelper.getSplineFlingDistance(velocityY); fling( child, (int) distance + scrollY, velocityY, scrollY); return super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed); } private void fling(final View pChild, final int pMaxOffset, final float pVelocityY, final int pStartY) { stopFling(pChild); mIsFlingRunning = true; if (mScroller == null) { mScroller = ScrollerCompat.create(mContext); } mScroller.fling( 0, pStartY, // current 0, Math.round(pVelocityY), // velocity. 0, 0, // x 0, pMaxOffset); // y if (mScroller.computeScrollOffset()) { mFlingRunnable = new FlingRunnable(pChild); ViewCompat.postOnAnimation(pChild, mFlingRunnable); } } private void stopFling(final View pChild) { if (mFlingRunnable != null) { pChild.removeCallbacks(mFlingRunnable); mFlingRunnable = null; } } private class FlingRunnable implements Runnable { private final View mView; FlingRunnable(final View pView) { mView = pView; } @Override public void run() { if (mView != null && mScroller != null) { if (mScroller.computeScrollOffset()) { mIsFlingRunning = true; // Post ourselves so that we run on the next animation ViewCompat.postOnAnimation(mAppBarLayout, this); } } else { mIsFlingRunning = false; } } } 
0
source

All Articles