模仿京东-上下左右滑动冲突
16lz
2022-05-18
项目
Conflict_project
图片实例
解决几个冲突
- 上面RecyclerView的高度扩宽
- 头部和下面ViewPager的同时滑动
- 头部隐藏后,ViewPager中RecyclerView继续滑动
解决步骤
1. 扩宽头部RecyclerView
布局加入这个,自适应高度
android:layout_width="match_parent"android:layout_height="wrap_content"
2. 解决冲突
public class NestedScrollLayout extends NestedScrollView { private View topView; //头部的View private ViewGroup contentView; // ViewPager中的ReyclerView private static final String TAG = "NestedScrollLayout"; //TAG public NestedScrollLayout(Context context) { this(context, null); init(); } public NestedScrollLayout(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); init(); } public NestedScrollLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); init(); } public NestedScrollLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr); init(); } private FlingHelper mFlingHelper; // veltociy和distance的转换 int totalDy = 0; /** * 用于判断RecyclerView是否在fling */ boolean isStartFling = false; /** * 记录当前滑动的y轴加速度 */ private int velocityY = 0; private void init() { mFlingHelper = new FlingHelper(getContext()); setOnScrollChangeListener(new View.OnScrollChangeListener() { //监听自己(NestedScrollView)滑动 @Override public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) { if (isStartFling) { totalDy = 0; isStartFling = false; } if (scrollY == 0) { // 到达顶部的时候 Log.i(TAG, "TOP SCROLL"); // refreshLayout.setEnabled(true); } // topView完全消失了,该子View处理了 if (scrollY == (getChildAt(0).getMeasuredHeight() - v.getMeasuredHeight())) { Log.i(TAG, "BOTTOM SCROLL"); dispatchChildFling(); } //在RecyclerView fling情况下,记录当前RecyclerView在y轴的偏移 totalDy += scrollY - oldScrollY; } }); } private void dispatchChildFling() { if (velocityY != 0) { // 滑动的速度,和distance可以相互转换 // 转换成距离 Double splineFlingDistance = mFlingHelper.getSplineFlingDistance(velocityY); if (splineFlingDistance > totalDy) { // 转换成velocityY childFling(mFlingHelper.getVelocityByDistance(splineFlingDistance - Double.valueOf(totalDy))); } } // 处理完之后,恢复默认值 totalDy = 0; velocityY = 0; } private void childFling(int velY) { RecyclerView childRecyclerView = getChildRecyclerView(contentView); // 找到子View(RecyclerView) if (childRecyclerView != null) { childRecyclerView.fling(0, velY); //fling事件传出去 } } @Override public void fling(int velocityY) { // 自己的fling super.fling(velocityY); if (velocityY <= 0) { this.velocityY = 0; } else { isStartFling = true; //开始fling滑动 this.velocityY = velocityY; //滑动的速度 } } @Override protected void onFinishInflate() { super.onFinishInflate(); //顶部的View topView = ((ViewGroup) getChildAt(0)).getChildAt(0); //下面的RecyclerView, contentView = (ViewGroup) ((ViewGroup) getChildAt(0)).getChildAt(1); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // 调整contentView的高度为父容器高度,使之填充布局,避免父容器滚动后出现空白 super.onMeasure(widthMeasureSpec, heightMeasureSpec); ViewGroup.LayoutParams lp = contentView.getLayoutParams(); lp.height = getMeasuredHeight(); //测量的是整个父View的高度 contentView.setLayoutParams(lp); } @Override public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) { Log.i("NestedScrollLayout", getScrollY()+"::onNestedPreScroll::"+topView.getMeasuredHeight()); // 向上滑动。若当前topview可见,需要将topview滑动至不可见 boolean hideTop = dy > 0 && getScrollY() < topView.getMeasuredHeight(); if (hideTop) { scrollBy(0, dy); //相对滑动了多少位置 consumed[1] = dy; // 消费掉y轴的滑动事件 } } private RecyclerView getChildRecyclerView(ViewGroup viewGroup) { for (int i = 0; i < viewGroup.getChildCount(); i++) { View view = viewGroup.getChildAt(i); if (view instanceof RecyclerView && view.getClass() == NestedLogRecyclerView.class) { return (RecyclerView) viewGroup.getChildAt(i); } else if (viewGroup.getChildAt(i) instanceof ViewGroup) { ViewGroup childRecyclerView = getChildRecyclerView((ViewGroup) viewGroup.getChildAt(i)); if (childRecyclerView instanceof RecyclerView) { return (RecyclerView) childRecyclerView; } } continue; } return null; }}
工具类
FlingHelper
public class FlingHelper { private static float DECELERATION_RATE = ((float) (Math.log(0.78d) / Math.log(0.9d))); private static float mFlingFriction = ViewConfiguration.getScrollFriction(); private static float mPhysicalCoeff; public FlingHelper(Context context) { mPhysicalCoeff = context.getResources().getDisplayMetrics().density * 160.0f * 386.0878f * 0.84f; } private double getSplineDeceleration(int i) { return Math.log((double) ((0.35f * ((float) Math.abs(i))) / (mFlingFriction * mPhysicalCoeff))); } private double getSplineDecelerationByDistance(double d) { return ((((double) DECELERATION_RATE) - 1.0d) * Math.log(d / ((double) (mFlingFriction * mPhysicalCoeff)))) / ((double) DECELERATION_RATE); } public double getSplineFlingDistance(int i) { return Math.exp(getSplineDeceleration(i) * (((double) DECELERATION_RATE) / (((double) DECELERATION_RATE) - 1.0d))) * ((double) (mFlingFriction * mPhysicalCoeff)); } public int getVelocityByDistance(double d) { return Math.abs((int) (((Math.exp(getSplineDecelerationByDistance(d)) * ((double) mFlingFriction)) * ((double) mPhysicalCoeff)) / 0.3499999940395355d)); }}
更多相关文章
- android clipChildren与clipToPadding
- Android下如何计算要显示的字符串所占的宽度和高度
- Android(安卓)自定义View 使用VelocityTracker记录滑动速度
- Android(安卓)之 ScrollView(垂直滑动)组件
- 必须知道的Android屏幕自适应解决方案
- 转 Android监听键盘弹出收起
- ListView分隔线
- Android事件分发机制四:学了事件分发有什么用?
- Android事件分发机制四:学了事件分发有什么用?