滑動coordinatorLayout 後不跟手,反向滑動不能暫停之前的滑動。需要在AppBarLayout使用自定義的behavior
效果圖
首先,新建behavior文件AppBarLayoutBehavior.java
import android.content.Context;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CoordinatorLayout;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.OverScroller;
import java.lang.reflect.Field;
public class AppBarLayoutBehavior extends AppBarLayout.Behavior {
private static final String TAG = "AppbarLayoutBehavior";
private static final int TYPE_FLING = 1;
private boolean isFlinging;
private boolean shouldBlockNestedScroll;
public AppBarLayoutBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
LogUtil.d(TAG, "onInterceptTouchEvent:" + child.getTotalScrollRange());
shouldBlockNestedScroll = isFlinging;
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
//手指觸摸屏幕的時候停止fling事件
stopAppbarLayoutFling(child);
break;
default:
break;
}
return super.onInterceptTouchEvent(parent, child, ev);
}
/**
* 反射獲取私有的flingRunnable 屬性,考慮support 28以後變量名修改的問題
* @return Field
* @throws NoSuchFieldException
*/
private Field getFlingRunnableField() throws NoSuchFieldException {
Class<?> superclass = this.getClass().getSuperclass();
try {
// support design 27及一下版本
Class<?> headerBehaviorType = null;
if (superclass != null) {
headerBehaviorType = superclass.getSuperclass();
}
if (headerBehaviorType != null) {
return headerBehaviorType.getDeclaredField("mFlingRunnable");
}else {
return null;
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
// 可能是28及以上版本
Class<?> headerBehaviorType = superclass.getSuperclass().getSuperclass();
if (headerBehaviorType != null) {
return headerBehaviorType.getDeclaredField("flingRunnable");
} else {
return null;
}
}
}
/**
* 反射獲取私有的scroller 屬性,考慮support 28以後變量名修改的問題
* @return Field
* @throws NoSuchFieldException
*/
private Field getScrollerField() throws NoSuchFieldException {
Class<?> superclass = this.getClass().getSuperclass();
try {
// support design 27及一下版本
Class<?> headerBehaviorType = null;
if (superclass != null) {
headerBehaviorType = superclass.getSuperclass();
}
if (headerBehaviorType != null) {
return headerBehaviorType.getDeclaredField("mScroller");
}else {
return null;
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
// 可能是28及以上版本
Class<?> headerBehaviorType = superclass.getSuperclass().getSuperclass();
if (headerBehaviorType != null) {
return headerBehaviorType.getDeclaredField("scroller");
}else {
return null;
}
}
}
/**
* 停止appbarLayout的fling事件
* @param appBarLayout
*/
private void stopAppbarLayoutFling(AppBarLayout appBarLayout) {
//通過反射拿到HeaderBehavior中的flingRunnable變量
try {
Field flingRunnableField = getFlingRunnableField();
Field scrollerField = getScrollerField();
if (flingRunnableField != null) {
flingRunnableField.setAccessible(true);
}
if (scrollerField != null) {
scrollerField.setAccessible(true);
}
Runnable flingRunnable = null;
if (flingRunnableField != null) {
flingRunnable = (Runnable) flingRunnableField.get(this);
}
OverScroller overScroller = (OverScroller) scrollerField.get(this);
if (flingRunnable != null) {
LogUtil.d(TAG, "存在flingRunnable");
appBarLayout.removeCallbacks(flingRunnable);
flingRunnableField.set(this, null);
}
if (overScroller != null && !overScroller.isFinished()) {
overScroller.abortAnimation();
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
@Override
public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child,
View directTargetChild, View target,
int nestedScrollAxes, int type) {
LogUtil.d(TAG, "onStartNestedScroll");
stopAppbarLayoutFling(child);
return super.onStartNestedScroll(parent, child, directTargetChild, target,
nestedScrollAxes, type);
}
@Override
public void onNestedPreScroll(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);
//type返回1時,表示當前target處於非touch的滑動,
//該bug的引起是因爲appbar在滑動時,CoordinatorLayout內的實現NestedScrollingChild2接口的滑動
//子類還未結束其自身的fling
//所以這裏監聽子類的非touch時的滑動,然後block掉滑動事件傳遞給AppBarLayout
if (type == TYPE_FLING) {
isFlinging = true;
}
if (!shouldBlockNestedScroll) {
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);
}
}
@Override
public void onNestedScroll(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);
}
}
@Override
public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout abl,
View target, int type) {
LogUtil.d(TAG, "onStopNestedScroll");
super.onStopNestedScroll(coordinatorLayout, abl, target, type);
isFlinging = false;
shouldBlockNestedScroll = false;
}
private static class LogUtil{
static void d(String tag, String string){
Log.d(tag,string);
}
}
}
整個頁面佈局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/parentLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<RelativeLayout
android:id="@+id/tool"
style="@style/topbar_bg"
android:background="@color/titleColor">
<ImageView style="@style/topbar_return_img" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/titleText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/details"
android:textColor="@color/white"
android:textSize="16sp" />
</LinearLayout>
</RelativeLayout>
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/bottomLayout"
android:layout_below="@+id/tool"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:layout_behavior=".utils.AppBarLayoutBehavior">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:statusBarScrim="@android:color/transparent">
<LinearLayout
android:id="@+id/itemLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/shape_press_bound"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="12dp"
android:layout_marginTop="10dp"
android:layout_marginRight="12dp"
android:layout_marginBottom="5dp">
<TextView
android:id="@+id/postInfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/userName"
android:layout_alignLeft="@+id/userName"
android:layout_marginTop="8dp"
android:text=""
android:textColor="@color/second_text_color"
android:textSize="12sp" />
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_marginTop="15dp"
android:background="@color/color_background_grey" />
</LinearLayout>
</android.support.design.widget.CollapsingToolbarLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioGroup
android:id="@+id/radioGroup"
android:layout_width="match_parent"
android:layout_height="44dp"
android:background="@color/white"
android:gravity="center_vertical"
android:orientation="horizontal"
app:layout_scrollFlags="scroll">
<RadioButton
android:id="@+id/replyCount"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:button="@null"
android:checked="true"
android:paddingLeft="12dp"
android:paddingRight="30dp"
android:text="@string/comment_count"
android:textColor="@color/selector_tweet_detail_tab"
android:textSize="14sp" />
<Space
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1" />
<RadioButton
android:id="@+id/likeCount"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:button="@null"
android:paddingLeft="30dp"
android:paddingRight="15dp"
android:text="@string/like_count"
android:textColor="@color/selector_tweet_detail_tab"
android:textSize="14sp" />
</RadioGroup>
</LinearLayout>
</android.support.design.widget.AppBarLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<View
android:layout_width="match_parent"
android:layout_height="2px"
android:background="@color/colorLine" />
<!-- viewpager可以有多個fragment,裏面可以用smartRefreshLayout -->
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
</RelativeLayout>