美文网首页高级UI自定义控件
android 粗略的 仿京东首页 嵌套方式滚动 V2版本

android 粗略的 仿京东首页 嵌套方式滚动 V2版本

作者: 一个冬季 | 来源:发表于2020-04-27 18:44 被阅读0次
简要说明

V1版本的地址 之前写过一篇,V1版本的思路,但是感觉写的还不是很好。很早之前看到了一篇写的很好的文章,文章地址 Android嵌套滑动机制实战演练 我就在想是否可以结合他的再来改改,于是就有了V2版本 嘻嘻。

github 地址 里面的MainActivity 是V1的代码,ThiredActivity 是V2代码

效果图.gif
开发的时候遇到的问题

1、外层是RecyclerView且含有多type,里面其中一个type里面含有recyclerview。在处理滑动过程中发现,无论滑动的是外层recyclerview,还是里层的recyclerview,startNestedScroll 都会被调用(先调用父),但是 dispatchNestedPreScroll 只有最外层的才会被调用。问题就在这里,如果要实现嵌套滑动,需要内部的 dispatchNestedPreScroll 调用才能正常执行逻辑


xml简单结构图.jpg
解决问题

既然 子recyclerview里面的 dispatchNestedPreScroll 没办法调用,我们就要换个思路来解决问题


简单结构图.jpg

这里比较重要的是 NestedFrameLayout,它 implements NestedScrollingParent3 ,我们需要在 onNestedPreScroll 里面进行处理,在处理的时候,我们需要注意 MyThiredBottomLinLerLayout.getTop 是否为0,如果是0,我们就只能够滚动 childRecyclerView,否则就滚动 rootRecyclerView

 @Override
    public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {
        if (target instanceof RecyclerView) {
            if (dy > 0) {//手指向上
                if (bottomThiredLinLerLayout != null) {
                    if (bottomThiredLinLerLayout.getTop() != 0) {  只能滚动父的recyclerView
                        rootRecyclerView.scrollBy(0, dy);
                    } else if (bottomThiredLinLerLayout.getTop() == 0) { 我们只能滚动childRecyclerview
                        if (childRecyclerView != null) {
                            bottomThiredLinLerLayout.toDoNestedPreScroll(dy);  这里是处理标题隐藏和显示的地方
                            childRecyclerView.scrollBy(0, dy);
                            consumed[1] = dy;
                        }
                    }
                }else {
                    rootRecyclerView.scrollBy(0, dy);
                }
            }

            if (dy < 0) {//手指向下
                if (bottomThiredLinLerLayout!=null){
                    if (bottomThiredLinLerLayout.getTop() != 0) {
                        rootRecyclerView.scrollBy(0, dy);
                        consumed[1] = dy;
                    } else if (bottomThiredLinLerLayout.getTop() == 0) {
                        if (childRecyclerView != null) {
                            bottomThiredLinLerLayout.toDoNestedPreScroll(dy);
                            if (childRecyclerView.canScrollVertically(dy)) {
                                childRecyclerView.scrollBy(0, dy);
                                consumed[1] = dy;
                            } else {
                                rootRecyclerView.scrollBy(0, dy);
                            }
                        }
                    }
                }else {
                    rootRecyclerView.scrollBy(0, dy);
                }
            }

        }
    }

MyThiredBottomLinLerLayout 这个也是一个很重要的类,在V1版本的时候,我们 implements NestedScrollingParent3 接口,但是!!!如果根布局是RecyclerView 里面的一个Type为 RecyclerView ,我们滚动childRecyclerView,虽然会触发 onStartNestedScroll,但是不会触发 dispatchNestedPreScroll ,初步怀疑是因为根RecyclerView return fase 导致的。最先调用 dispatchNestedPreScroll 是根recyclerView

 public boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed,
            @Nullable int[] offsetInWindow, @NestedScrollType int type) {
        if (isNestedScrollingEnabled()) {
            final ViewParent parent = getNestedScrollingParentForType(type); 这里返回的parent 为 null ,该行意思为,是否含有嵌套的Parent
            if (parent == null) {
                return false;
            }

            if (dx != 0 || dy != 0) {
                int startX = 0;
                int startY = 0;
                if (offsetInWindow != null) {
                    mView.getLocationInWindow(offsetInWindow);
                    startX = offsetInWindow[0];
                    startY = offsetInWindow[1];
                }

                if (consumed == null) {
                    consumed = getTempNestedScrollConsumed();
                }
                consumed[0] = 0;
                consumed[1] = 0;
                ViewParentCompat.onNestedPreScroll(parent, mView, dx, dy, consumed, type);

.... 省略
}

所以这里我将 MyThiredBottomLinLerLayout 里面的 NestedScrollingParent3 实现去掉,直接换成了 toDoNestedPreScroll 方法

public void toDoNestedPreScroll(int dy){
        if (titleDescLayout == null) {
            for (int i = 0; i < getChildCount(); i++) {
                View view = getChildAt(i);
                if (view.getId() == R.id.ctl_thired_layout) {
                    titleDescLayout = view.findViewById(R.id.ll_thired_title_desc);
                    break;
                }
            }
        }

        if (dy > 0) {//手指向上
            if (isDescExOpen && !animatorIsRunning) {
                animatorIsRunning = true;
                ValueAnimator valueAnimator = ValueAnimator.ofFloat(1.0f, 0.1f);
                valueAnimator.setDuration(200);
                valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        float value = (float) animation.getAnimatedValue();
                        ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) titleDescLayout.getLayoutParams();
                        layoutParams.height = (int) (getTitleDescHeight() * value);
                        titleDescLayout.setLayoutParams(layoutParams);
                    }
                });
                valueAnimator.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        isDescExOpen = false;
                        animatorIsRunning = false;
                    }
                });
                valueAnimator.start();
            }


        }


        if (dy < 0) {//手指向下
            if (!isDescExOpen && !animatorIsRunning && !currentRecyclerView.canScrollVertically(dy)) {
                animatorIsRunning = true;
                ValueAnimator valueAnimator = ValueAnimator.ofFloat(0.1f, 1.0f);
                valueAnimator.setDuration(200);
                valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        float value = (float) animation.getAnimatedValue();
                        ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) titleDescLayout.getLayoutParams();
                        layoutParams.height = (int) (getTitleDescHeight() * value);
                        titleDescLayout.setLayoutParams(layoutParams);
                    }
                });
                valueAnimator.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        isDescExOpen = true;
                        animatorIsRunning = false;
                    }
                });
                valueAnimator.start();
            }
        }
    }

相关文章

网友评论

    本文标题:android 粗略的 仿京东首页 嵌套方式滚动 V2版本

    本文链接:https://www.haomeiwen.com/subject/oqiywhtx.html