下面就用思路二來分析一下如何實現php
public class NestedRecyclerView extends RecyclerView {
private float topPadding = Utils.dp2Px(50);
private float scrollSlop = Utils.dp2Px(50); //滑動超過這個距離鬆手後自動自動滑動到頂部
private float downY;
private float moveY;
private float deltaMoveY;
private float deltaDownMoveY;
private float lastMoveY;
public OverScroller mScroller;
private int firstCompletelyVisiblePosition;
public NestedRecyclerView(@NonNull Context context) {
this(context, null);
}
public NestedRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
mScroller = new OverScroller(context);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d("NestedRecyclerView", "ACTION_DOWN");
downY = event.getRawY();
lastMoveY = event.getRawY();
break;
}
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d("NestedRecyclerView", "ACTION_DOWN");
downY = event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
moveY = event.getRawY();
deltaMoveY = moveY - lastMoveY;
deltaDownMoveY = moveY - downY;
//向上滑動 手指滑動到 recyclerview 頂部或者以上 觸發嵌套滑動
//event.getY() <= 0 且 getTop() - ((View) getParent()).getScrollY() > topPadding
if (deltaMoveY < 0) {
if (event.getY() <= 0) {
if (getTop() - ((View) getParent()).getScrollY() > topPadding) {
setNestedScrollingEnabled(true);
startNestedScroll(SCROLL_AXIS_VERTICAL);
} else {
setNestedScrollingEnabled(false);
}
} else {
setNestedScrollingEnabled(false);
}
} else {
//向下滑動
//先向下滑動 recyclerview,等待 recyclerview 所有展示後觸發嵌套滑動
GridLayoutManager layoutManager = ((GridLayoutManager) getLayoutManager());
firstCompletelyVisiblePosition = layoutManager.findFirstCompletelyVisibleItemPosition();
if (firstCompletelyVisiblePosition == 0 && ((View) getParent()).getScrollY() > 0) {
setNestedScrollingEnabled(true);
startNestedScroll(SCROLL_AXIS_VERTICAL);
} else {
setNestedScrollingEnabled(false);
}
}
lastMoveY = moveY;
break;
case MotionEvent.ACTION_UP:
int parentScrollY = ((View) getParent()).getScrollY();
int startY = parentScrollY;
int dy;
if (deltaDownMoveY < 0) {
//向上滑動切滑動距離超過 scrollSlop 滑動到頂部
//向上滑動切滑動距離不超過 scrollSlop 滑回到底部
if (parentScrollY >= scrollSlop) {
dy = (int) (getTop() - ((View) getParent()).getScrollY() - topPadding);
} else {
dy = -parentScrollY;
}
} else {
//向下滑動切滑動距離超過 scrollSlop 滑動到底部
//向下滑動切滑動距離不超過 scrollSlop 滑回到頂部
if (getTop() - ((View) getParent()).getScrollY() > scrollSlop + topPadding) {
dy = -parentScrollY;
} else {
dy = (int) (getTop() - ((View) getParent()).getScrollY() - topPadding);
}
}
mScroller.startScroll(0, startY, 0
, dy, 300);
((View) getParent()).invalidate();
break;
}
return super.onTouchEvent(event);
}
public OverScroller getScroller() {
return mScroller;
}
}
複製代碼
因爲RecyclerView默認實現了NestedScrollingChild2,不須要咱們本身實現NestedScrollingChild。java
重寫RecyclerView的onTouchEvent方法,在ACTION_MOVE裏面合適的時候開啓/禁止彈性滑動,具體邏輯參考前面流程圖和代碼註釋。android
在ACTION_UP的時候經過 Scroller 實現彈性滑動的效果,關鍵是計算出 dy,代碼註釋裏面寫的很清楚。app
關於 Scroller 的使用參考這裏ide
public class LinearLayoutNestScrollParent extends LinearLayout implements NestedScrollingParent {
private NestedScrollingParentHelper mParentHelper;
private View imgView;
private NestedRecyclerView recyclerview;
public LinearLayoutNestScrollParent(Context context) {
this(context, null);
}
public LinearLayoutNestScrollParent(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
mParentHelper = new NestedScrollingParentHelper(this);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
imgView = findViewById(R.id.img);
recyclerview = findViewById(R.id.rv_photos);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int imgHeight = imgView.getMeasuredHeight();
//從新測量高度
int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight() + imgHeight, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, newHeightMeasureSpec);
}
@Override
public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
if (target instanceof RecyclerView) {
return true;
}
return false;
}
@Override
public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
mParentHelper.onNestedScrollAccepted(child, target, nestedScrollAxes);
}
@Override
public void onStopNestedScroll(View target) {
mParentHelper.onStopNestedScroll(target);
}
//先於 child 滾動
@Override
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
scrollBy(0, dy);//滾動
consumed[1] = dy;//告訴child我消費了多少
}
//後於child滾動
@Override
public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
}
//返回值:是否消費了fling
@Override
public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
return false;
}
//返回值:是否消費了fling
@Override
public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
return false;
}
@Override
public int getNestedScrollAxes() {
return mParentHelper.getNestedScrollAxes();
}
@Override
public void computeScroll() {
OverScroller scroller = recyclerview.getScroller();
if (scroller.computeScrollOffset()) {
scrollTo(scroller.getCurrX(), scroller.getCurrY());
invalidate();
}
}
}
複製代碼
實現NestedScrollingParent接口,只要實現onNestedScroll這個方法,所有消費 NestedScrollingChild傳來的 dy 。佈局
另外須要注意的onMeasure方法,從新測量高度,不然上滑時候RecyclerView下面部分會出現空白。this
<?xml version="1.0" encoding="utf-8"?>
<cn.feng.xhsimageview.views.LinearLayoutNestScrollParent 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:orientation="vertical">
<ImageView android:id="@+id/img" android:layout_width="match_parent" android:layout_height="wrap_content"/>
<cn.feng.xhsimageview.views.NestedRecyclerView android:id="@+id/rv_photos" android:layout_width="match_parent" android:layout_height="0dp" android:layout_marginTop="2dp" android:layout_weight="1" />
</cn.feng.xhsimageview.views.LinearLayoutNestScrollParent>
複製代碼