沃梦达 / IT编程 / 移动开发 / 正文

NestScrollView嵌套RecyclerView实现淘宝首页滑动效果

这篇文章主要介绍了NestScrollView嵌套RecyclerView实现淘宝首页滑动效果,主要实现淘宝首页嵌套滑动,中间tab吸顶效果,以及介绍NestScrollView嵌套RecyclerView处理滑动冲突的方法,需要的朋友可以参考下

再结合RecyclerView的ACTION_MOVE来看:


public boolean onTouchEvent(MotionEvent e) {
  switch (action) {
    case MotionEvent.ACTION_MOVE: {
      if (dispatchNestedPreScroll(
        canScrollHorizontally ? dx : 0,
        canScrollVertically ? dy : 0,
        mReusableIntPair, mScrollOffset, TYPE_TOUCH
      )) {
        //dispatchNestedPreScroll返回了false,此处的if语句不会执行,因此RecyclerView也会滑动
        dx -= mReusableIntPair[0];
        dy -= mReusableIntPair[1];
        // Updated the nested offsets
        mNestedOffsets[0] += mScrollOffset[0];
        mNestedOffsets[1] += mScrollOffset[1];
        // Scroll has initiated, prevent parents from intercepting
        getParent().requestDisallowInterceptTouchEvent(true);
      }
      
      if (scrollByInternal(
        canScrollHorizontally ? dx : 0,
        canScrollVertically ? dy : 0,
        e)) {
        getParent().requestDisallowInterceptTouchEvent(true);
      }
    } break;
  }
  return true;
}

因此,我们,在NestedScrollView的onNestedPreScroll方法中,处理完滑动后,通过consumed告诉RecyclerView我滑动了多少,这样

RecyclerView会重新设置dx、dy的值,因此RecyclerView就不会跟着滑动了


public class StickyNestedScrollLayout extends NestedScrollView {
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        int count = getChildCount();
        if(count == 1) {
            View firstChild = getChildAt(0);
            if(firstChild != null && firstChild instanceof ViewGroup) {
                int childCount = ((ViewGroup) firstChild).getChildCount();
                if(childCount > 1) {
                    topView = ((ViewGroup) firstChild).getChildAt(0);
                    contentView = ((ViewGroup) firstChild).getChildAt(1);
                }
            }
        }
    }

    @Override
    public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {
        boolean topIsShow = getScrollY() >=0 && getScrollY() < topView.getHeight();
        if(topIsShow) {
            scrollBy(0, dy);
            //告诉RecyclerView,我滑动了多少距离
            consumed[1] = dy;
        } else {
            super.onNestedPreScroll(target, dx, dy, consumed, type);
        }
    }
}

四.实现惯性滑动

实现思路:

记录父控件惯性滑动的速度判断NestedScrollView是否滚动到底部,若滚动到底部,判断子控件是否需要继续滚动滚动将惯性滑动的速度转化成距离,计算子控件应滑的距离 = 惯性距离 - 父控件已滑动距离,并将子控件应滑的距离转化成速度交给子控件进行惯性滑动

1.记录父控件惯性滑动的速度


public void fling(int velocityY) {
  super.fling(velocityY);
  if (velocityY <= 0) {
  	mVelocityY = 0;
  } else {
  	mVelocityY = velocityY;
  }
}

2.判断NestedScrollView是否滚动到底部,若滚动到底部,判断子控件是否需要继续滚动


@Override
protected void onScrollChanged(int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
  super.onScrollChanged(scrollX, scrollY, oldScrollX, oldScrollY);
  /*
         * scrollY == 0 即还未滚动
         * scrollY == getChildAt(0).getMeasuredHeight() - v.getMeasuredHeight()即滚动到底部了
         */
  //判断NestedScrollView是否滚动到底部,若滚动到底部,判断子控件是否需要继续滚动
  if (scrollY == getChildAt(0).getMeasuredHeight() - this.getMeasuredHeight()) {
    dispatchChildFling();
  }
  //累计自身滚动的距离
  mConsumedY += scrollY - oldScrollY;
}

3.将惯性滑动的速度转化成距离,计算子控件应滑的距离 = 惯性距离 - 父控件已滑动距离,并将子控件应滑的距离转化成速度交给子控件进行惯性滑动


private void dispatchChildFling() {
    if(mFlingHelper == null) {
      mFlingHelper = new FlingHelper(getContext());
    }
    if (mVelocityY != 0) {
        //将惯性滑动速度转化成距离
        double distance = mFlingHelper.getSplineFlingDistance(mVelocityY);
        //计算子控件应该滑动的距离 = 惯性滑动距离 - 已滑距离
        if (distance > mConsumedY) {
            RecyclerView recyclerView = getChildRecyclerView(mContentView);
            if (recyclerView != null) {
                //将剩余滑动距离转化成速度交给子控件进行惯性滑动
                int velocityY = mFlingHelper.getVelocityByDistance(distance - mConsumedY);
                recyclerView.fling(0, velocityY);
            }
        }
    }

    mConsumedY = 0;
    mVelocityY = 0;
}

//递归获取子控件RecyclerView
private RecyclerView getChildRecyclerView(ViewGroup viewGroup) {
  for (int i = 0; i < viewGroup.getChildCount(); i++) {
    View view = viewGroup.getChildAt(i);
    if (view instanceof RecyclerView && Objects.requireNonNull(((RecyclerView) view).getLayoutManager()).canScrollVertically()) {
      return (RecyclerView) view;
    } else if (viewGroup.getChildAt(i) instanceof ViewGroup) {
      RecyclerView childRecyclerView = getChildRecyclerView((ViewGroup) viewGroup.getChildAt(i));
      if (childRecyclerView != null && Objects.requireNonNull((childRecyclerView).getLayoutManager()).canScrollVertically()) {
        return childRecyclerView;
      }
    }
  }
  return null;
}

到此这篇关于NestScrollView嵌套RecyclerView实现淘宝首页滑动效果的文章就介绍到这了,更多相关NestScrollView嵌套RecyclerView内容请搜索编程学习网以前的文章希望大家以后多多支持编程学习网!

本文标题为:NestScrollView嵌套RecyclerView实现淘宝首页滑动效果