AppBarLayout has a horrible design that doesn’t have its own Fling and RecyclerView doesn’t have it. This paper intends to use the method of custom Behavior to solve this problem, which should be the simplest method on the Internet nowadays. Before I thought about my own solution, I simply searched some previous answers on the Internet, and found that the known answers are very troublesome. A lot of methods are to copy the AppBarLayout related code and then modify it simply. The workload is very large and complex. This article will introduce a method developed by the author himself. The advantage of this article is that you can only define two behaviors to achieve it.

1. The cause of the problem

HeaderBehavior (); HeaderBehavior ();

case MotionEvent.ACTION_UP: if (mVelocityTracker ! = null) { mVelocityTracker.addMovement(ev); MVelocityTracker.com puteCurrentVelocity (1, 0.01 f); mVelocityTracker.computeCurrentVelocity(1000); float yvel = mVelocityTracker.getYVelocity(mActivePointerId); fling(parent, child, -getScrollRangeForDragFling(child), 0, yvel); }Copy the code

Fling range is [- getScrollRangeForDragFling (child), 0], this leads to the top AppBarLayoutFling to immediately stop, reason is so very simple.

2. Solve problems

If we want to solve this problem, we have to go to the root. Fling is a problem that cannot be passed on. Let’s pass it on. How do we pass it on? This paper adopts nested sliding transmission.

(1). Customize AppBarLayout Behavior

The key to AppBarLayout Behavior lies in how to transfer Fling. Let’s look at the Behavior in three steps:

  1. willHeaderBehavior ,onTouchEventMethod and its associated method code are copied
  2. inAppBarLayoutWhile we Fling, we call our own Fling method (fing in this case), copying the code from the original Fling method.
  3. rewriteFlingRunnableTo transfer the Fling event smoothly.

Among these, we need to note one thing:

  1. When the fling method is called,minOffsetPass toInteger.MIN_VALUEThe Fling event is not confined to any one place.
@Override public boolean onTouchEvent(CoordinatorLayout parent, AppBarLayout child, ACTION_UP: If (velocityTracker!) {// case MotionEvent.ACTION_UP: If (velocityTracker! = null) { velocityTracker.addMovement(ev); velocityTracker.computeCurrentVelocity(1000); float yvel = velocityTracker.getYVelocity(activePointerId); flingV2(parent, child, Integer.MIN_VALUE, 0, yvel); } / /......}Copy the code

Fling Fling Fling Fling Fling Fling Fling Fling Fling Fling Fling Fling Fling fling fling fling fling fling fling fling fling fling fling fling fling Let’s take a look at the FlingRunnable class:

private class FlingRunnable implements Runnable { private final CoordinatorLayout parent; private final AppBarLayout layout; FlingRunnable(CoordinatorLayout parent, AppBarLayout layout) { this.parent = parent; this.layout = layout; } @Override public void run() { if (layout ! = null && scroller ! = null) { if (scroller.computeScrollOffset()) { scroll(); } else { onFlingFinished(parent, layout); }} private void scroll() {// If AppBarLayout slides to the threshold, Now need to fling events to pass down the if (scroller. GetCurrY () < = - getScrollRangeForDragFling (layout) && scroller. GetStartX () > scroller.getFinalY()) { setHeaderTopBottomOffset(parent, layout, -getScrollRangeForDragFling(layout)); if (layout.startNestedScroll(View.SCROLL_AXIS_VERTICAL)) { layout.dispatchNestedFling(scroller.getCurrVelocity(), scroller.getCurrVelocity(), false); } scroller.forceFinished(true); } else {// If AppBarLayout has not reached the threshold, just slide happily. setHeaderTopBottomOffset(parent, layout, scroller.getCurrY()); } ViewCompat.postOnAnimation(layout, this); }}Copy the code

This is the end of the AppBarLayout custom Behavior process, and then we can look at the Behavior of RecyclerView.

(2). Custom RecyclerView Behavior

The code is as follows:

public class FlingScrollingViewBehavior extends AppBarLayout.ScrollingViewBehavior { public FlingScrollingViewBehavior()  { } public FlingScrollingViewBehavior(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) { return true; } @Override public boolean onNestedFling(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, float velocityX, float velocityY, boolean consumed) { if (child ! = target) { ((RecyclerView) (child)).fling((int) velocityX, (int) velocityY); } return true; }}Copy the code

And then we put in XMLBehaviorYou bind, and you see,AppBarLayoutYou can Fling it and it looks like this:

3. Summary

This method is very simple and ends here, not as long as other methods on the web. Here, I make a simple summary of this article.

  1. Customize the AppBarLayout Behavior to ensure that the Fling event is passed.
  2. Custom RecyclerView Behavior, you canRecyclerViewThe fling method is used to fling.