問(wèn)題描述
先看出現(xiàn)抖動(dòng)時(shí)的錄屏:
如何復(fù)現(xiàn):
只需要在A(yíng)ndroid Studio中按照谷歌官方模板, 生成一個(gè)Scrolling Activity:
修改它的布局文件 activity_scrolling.xml 把Appbarlayout控件的高度設(shè)置的大一點(diǎn), 這里使用380dp. 不修改也能復(fù)現(xiàn)這個(gè)問(wèn)題, 但是高度值修改的大一點(diǎn), 容易復(fù)現(xiàn).
如下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".ScrollingActivity">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="380dp"
android:fitsSystemWindows="true"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:toolbarId="@+id/toolbar">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<include layout="@layout/content_scrolling" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="16dp"
app:layout_anchor="@id/app_bar"
app:layout_anchorGravity="bottom|end"
app:srcCompat="@android:drawable/ic_dialog_email" />
</android.support.design.widget.CoordinatorLayout>
編譯, 運(yùn)行:
顯示:
用手指輕輕滑動(dòng)CoordinatorLayout部分(藍(lán)色部分), 上滑, 快速抬起手指, 形成一個(gè)fling操作. 其實(shí)就是向上滑動(dòng)一下.
這時(shí), 整個(gè)CoordinatorLayout部分會(huì)向上移動(dòng)(fling), 在停止移動(dòng)之前, 在下面的白色區(qū)域(也就是xml布局中的NestedScrollView)來(lái)一個(gè)反向的滑動(dòng)(fling) , 這時(shí)整個(gè)頁(yè)面就會(huì)開(kāi)始或大或小的抖動(dòng), 非常明顯.
測(cè)試環(huán)境:
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:design:27.1.1'
implementation 'com.android.support:recyclerview-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
解決方案
為AppBarLayout這只自定義的behavior: FixAppBarLayoutBehavior.java
這個(gè)類(lèi)的具體代碼如下:
public class FixAppBarLayoutBehavior extends AppBarLayout.Behavior {
private static final String TAG = "AppBarLayoutBehavior";
public FixAppBarLayoutBehavior() {
super();
}
public FixAppBarLayoutBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
// --------------begin added by shaopx -------------
@Override
public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
if (ev.getAction() == ACTION_DOWN) {
Object scroller = getSuperSuperField(this, "mScroller");
if (scroller != null && scroller instanceof OverScroller) {
OverScroller overScroller = (OverScroller) scroller;
overScroller.abortAnimation();
}
}
return super.onInterceptTouchEvent(parent, child, ev);
}
private Object getSuperSuperField(Object paramClass, String paramString) {
Field field = null;
Object object = null;
try {
field = paramClass.getClass().getSuperclass().getSuperclass().getDeclaredField(paramString);
field.setAccessible(true);
object = field.get(paramClass);
} catch (Exception e) {
e.printStackTrace();
}
return object;
}
// --------------------------- end
................... // 這里其他代碼可以忽略, 是為了解決另一個(gè)問(wèn)題的.
}
其實(shí)這帖子我們只需要關(guān)心上面的那個(gè)方法:onInterceptTouchEvent() 在其中, 當(dāng)檢測(cè)到down事件時(shí), 取消了mScroller的運(yùn)行(如果它正在scroll的話(huà)).
這里因?yàn)橐L(fǎng)問(wèn)父類(lèi)(其實(shí)是父類(lèi)的父類(lèi))的 mScroller變量. 所以用到了一個(gè)反射的工具方法, 這個(gè)沒(méi)什么可多說(shuō)的.
個(gè)人感覺(jué), 在appbarlayout滑動(dòng)時(shí), 必須有一個(gè)公開(kāi)的接口, 或者方法能夠停止它的fling滑動(dòng). 現(xiàn)在有嗎? 反正我沒(méi)找到, 就只能通過(guò)反射實(shí)現(xiàn)了
推薦閱讀
至于appbarlayout的滑動(dòng)原理, 推薦看另一篇博文:
https://blog.csdn.net/litefish/article/details/52588235
代碼路徑
詳細(xì)代碼已經(jīng)放到github上: (運(yùn)行示例時(shí)選擇第一個(gè)谷歌示例)
https://github.com/shaopx/CoordinatorLayoutExample