Skip to content Skip to sidebar Skip to footer

Recyclerview Fling Causes Laggy While Appbarlayout Is Scrolling

I have a layout as below

Solution 1:

I have found a solution (credits to yangchong: https://developpaper.com/coordinator-layout-sliding-jitter-problem/):

AppBarBehavior:

/**
 * <pre>
 *     @author yangchong
 *     blog  : https://github.com/yangchong211
 *     time  : 2019/03/13
 * desc: Custom Behavior
 * Revision: Solving Some Problems of AppbarLayout
 * 1) Fast sliding appbarLayout will rebound
 * 2) Fast sliding appbarLayout to fold state, immediately sliding down, there will be the problem of jitter.
 * 3) Slide appbarLayout, unable to stop sliding by pressing it with your finger
*/publicclassAppBarLayoutBehaviorextendsAppBarLayout.Behavior {

    privatestaticfinalStringTAG="AppbarLayoutBehavior";
    privatestaticfinalintTYPE_FLING=1;
    privateboolean isFlinging;
    privateboolean shouldBlockNestedScroll;

    publicAppBarLayoutBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @OverridepublicbooleanonInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
        LogUtil.d(TAG, "onInterceptTouchEvent:" + child.getTotalScrollRange());
        shouldBlockNestedScroll = isFlinging;
        switch (ev.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                // Stop fling when your finger touches the screen
                stopAppbarLayoutFling(child);
                break;
            default:
                break;
        }
        returnsuper.onInterceptTouchEvent(parent, child, ev);
    }

    /**
     * Reflect to get private flingRunnable attributes, considering the problem of variable name modification after support 28
     * @return Field
     * @throws NoSuchFieldException
     */private Field getFlingRunnableField()throws NoSuchFieldException {
        Class<?> superclass = this.getClass().getSuperclass();
        try {
            // Support design 27 and the following version
            Class<?> headerBehaviorType = null;
            if (superclass != null) {
                headerBehaviorType = superclass.getSuperclass();
            }
            if (headerBehaviorType != null) {
                return headerBehaviorType.getDeclaredField("mFlingRunnable");
            }else {
                returnnull;
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
            // Possibly 28 or more versions
            Class<?> headerBehaviorType = superclass.getSuperclass().getSuperclass();
            if (headerBehaviorType != null) {
                return headerBehaviorType.getDeclaredField("flingRunnable");
            } else {
                returnnull;
            }
        }
    }

    /**
     * Reflect to get private scroller attributes, considering the problem of variable name modification after support 28
     * @return Field
     * @throws NoSuchFieldException
     */private Field getScrollerField()throws NoSuchFieldException {
        Class<?> superclass = this.getClass().getSuperclass();
        try {
            // Support design 27 and the following version
            Class<?> headerBehaviorType = null;
            if (superclass != null) {
                headerBehaviorType = superclass.getSuperclass();
            }
            if (headerBehaviorType != null) {
                return headerBehaviorType.getDeclaredField("mScroller");
            }else {
                returnnull;
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
            // Possibly 28 or more versions
            Class<?> headerBehaviorType = superclass.getSuperclass().getSuperclass();
            if (headerBehaviorType != null) {
                return headerBehaviorType.getDeclaredField("scroller");
            }else {
                returnnull;
            }
        }
    }

    /**
     * Stop appbarLayout's fling event
     * @param appBarLayout
     */privatevoidstopAppbarLayoutFling(AppBarLayout appBarLayout) {
        // Get the flingRunnable variable in HeaderBehavior by reflectiontry {
            FieldflingRunnableField= getFlingRunnableField();
            FieldscrollerField= getScrollerField();
            if (flingRunnableField != null) {
                flingRunnableField.setAccessible(true);
            }
            if (scrollerField != null) {
                scrollerField.setAccessible(true);
            }
            RunnableflingRunnable=null;
            if (flingRunnableField != null) {
                flingRunnable = (Runnable) flingRunnableField.get(this);
            }
            OverScrolleroverScroller= (OverScroller) scrollerField.get(this);
            if (flingRunnable != null) {
                LogUtil.d (TAG,'Flying Runnable');
                appBarLayout.removeCallbacks(flingRunnable);
                flingRunnableField.set(this, null);
            }
            if (overScroller != null && !overScroller.isFinished()) {
                overScroller.abortAnimation();
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    @OverridepublicbooleanonStartNestedScroll(CoordinatorLayout parent, AppBarLayout child,
                                       View directTargetChild, View target,
                                       int nestedScrollAxes, int type) {
        LogUtil.d(TAG, "onStartNestedScroll");
        stopAppbarLayoutFling(child);
        returnsuper.onStartNestedScroll(parent, child, directTargetChild, target,
                nestedScrollAxes, type);
    }

    @OverridepublicvoidonNestedPreScroll(CoordinatorLayout coordinatorLayout,
                                  AppBarLayout child, View target,
                                  int dx, int dy, int[] consumed, int type) {
        LogUtil.d(TAG, "onNestedPreScroll:" + child.getTotalScrollRange()
                + " ,dx:" + dx + " ,dy:" + dy + " ,type:" + type);
        // When type returns to 1, it indicates that the current target is in a non-touch sliding.// The bug is caused by the sliding of the NestedScrolling Child2 interface in Coordinator Layout when the AppBar is sliding// The subclass has not ended its own fling// So here we listen for non-touch sliding of subclasses, and then block the sliding event to AppBarLayoutif (type == TYPE_FLING) {
            isFlinging = true;
        }
        if (!shouldBlockNestedScroll) {
            super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);
        }
    }

    @OverridepublicvoidonNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child,
                               View target, int dxConsumed, int dyConsumed, int
            dxUnconsumed, int dyUnconsumed, int type) {
        LogUtil.d(TAG, "onNestedScroll: target:" + target.getClass() + " ,"
                + child.getTotalScrollRange() + " ,dxConsumed:"
                + dxConsumed + " ,dyConsumed:" + dyConsumed + " " + ",type:" + type);
        if (!shouldBlockNestedScroll) {
            super.onNestedScroll(coordinatorLayout, child, target, dxConsumed,
                    dyConsumed, dxUnconsumed, dyUnconsumed, type);
        }
    }

    @OverridepublicvoidonStopNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout abl,
                                   View target, int type) {
        LogUtil.d(TAG, "onStopNestedScroll");
        super.onStopNestedScroll(coordinatorLayout, abl, target, type);
        isFlinging = false;
        shouldBlockNestedScroll = false;
    }

    privatestaticclassLogUtil{
        staticvoidd(String tag, String string){
            Log.d(tag,string);
        }
    }

}

Solution 2:

Put your recyclerview inside a nestedScrollView and remove the app:layout_behavior from recyclerview and make android:nestedScrollingEnabled="false" for recyclerview like this -

<android.support.v4.widget.NestedScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"

       <android.support.v7.widget.RecyclerViewandroid:id="@+id/rv_sample"android:layout_width="match_parent"android:layout_height="wrap_content"android:nestedScrollingEnabled="false"/></LinearLayout></android.support.v4.widget.NestedScrollView>

It should work fine!

Post a Comment for "Recyclerview Fling Causes Laggy While Appbarlayout Is Scrolling"