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"