ViewPager2嵌套ViewPager2(RecyclerView)滑动事件冲突

ViewPager+ViewPager就不会产生冲突,那是应为,官方ViewPager帮我们已经处理过,但是

ViewPager2,并未帮我们处理。

然而我们通过源码发现:getParent().requestDisallowInterceptTouchEvent(boolean)是决定是否拦截事件


    

        


    

1、官方ViewPager2处理:

官方通过get获取NestedScrollableHost第一层包裹的冲突View,如果冲突View层级深就会有问题

 private val child: View? get() = if (childCount > 0) getChildAt(0) else null

java:我们通过getChildView()遍历拿到底层冲突View,可以完美解决滑动冲突问题。

public class NestedScrollableHost extends FrameLayout {
    private boolean isChildHasSameDirection = true;
    private int touchSlop = 0;
    private float initialX = 0f;
    private float initialY = 0f;

    public NestedScrollableHost(@NonNull Context context) {
        super(context, null);
    }

    public NestedScrollableHost(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    @SuppressLint("NewApi")
    public NestedScrollableHost(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        touchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();

    }

    public final ViewPager2 getParentViewPager() {
        ViewParent parent = getParent();
        if (!(parent instanceof View)) {
            parent = null;
        }

        View v;
        for (v = (View) parent; v != null && !(v instanceof ViewPager2); v = (View) parent) {
            parent = v.getParent();
            if (!(parent instanceof View)) {
                parent = null;
            }
        }

        View viewPager = v;
        if (!(v instanceof ViewPager2)) {
            viewPager = null;
        }
        return (ViewPager2) viewPager;

    }

    public View getChildView() {
        return this.getChildCount() > 0 ? this.getChildAt(0) : null;
    }

    @SuppressLint("NewApi")
    private boolean canChildScroll(int orientation, Float delta) {
        View child = getChildView();
        if (child != null) {
            int direction = -(int) Math.signum(delta);
            switch (orientation) {
                case 0:
                    return child.canScrollHorizontally(direction);
                case 1:
                    return child.canScrollVertically(direction);
            }
        }
        return false;

    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        handleInterceptTouchEvent(ev);
        return super.onInterceptTouchEvent(ev);
    }


    private void handleInterceptTouchEvent(MotionEvent e) {
        ViewPager2 parentViewPager = getParentViewPager();
        if (parentViewPager != null) {
            int orientation = parentViewPager.getOrientation();
            int childOrientation = isChildHasSameDirection ? orientation : orientation == 0 ? 1 : 0;
            if (canChildScroll(childOrientation, -1.0f) || canChildScroll(childOrientation, 1.0f)) {
                if (e.getAction() == MotionEvent.ACTION_DOWN) {
                    initialX = e.getX();
                    initialY = e.getY();
                    getParent().requestDisallowInterceptTouchEvent(true);
                } else if (e.getAction() == MotionEvent.ACTION_MOVE) {
                    float dx = e.getX() - initialX;
                    float dy = e.getY() - initialY;
                    boolean isVpHorizontal = orientation == ViewPager2.ORIENTATION_HORIZONTAL;

                    // assuming ViewPager2 touch-slop is 2x touch-slop of child
                    float scaledDx = Math.abs(dx) * (isVpHorizontal ? 0.5f : 1f);
                    float scaledDy = Math.abs(dy) * (isVpHorizontal ? 1f : 0.5f);

                    if (scaledDx > touchSlop || scaledDy > touchSlop) {
                        if (isVpHorizontal == scaledDy > scaledDx) {
                            getParent().requestDisallowInterceptTouchEvent(false);
                        } else if (canChildScroll(orientation, isVpHorizontal ? dx : dy)) {
                            getParent().requestDisallowInterceptTouchEvent(true);
                        } else {
                            getParent().requestDisallowInterceptTouchEvent(false);
                        }

                    }
                }

            }
        }
    }

}

 处理思路,通过循环一层层去找

  public static View getChildScrollView(View view) {
        ArrayList unvisited = new ArrayList<>();
        unvisited.add(view);

        while (!unvisited.isEmpty()) {
            View child = unvisited.remove(0);
            if (child instanceof RecyclerView) {
                return child;
            }
            if (child instanceof ViewPager2) {
                return child;
            }
            if (!(child instanceof ViewGroup)) {
                continue;
            }
            ViewGroup viewGroup = (ViewGroup) child;
            for (int i = 0; i < viewGroup.getChildCount(); i++) {
                View childAt = viewGroup.getChildAt(i);
                View v = recursionChildScrollView(childAt);
                if (v != null) {
                    unvisited.add(v);
                }
            }
        }
        return null;
    }

    private static View recursionChildScrollView(View view) {
        if (view != null) {
            ViewGroup viewGroup = (ViewGroup) view;
            for (int i = 0; i < viewGroup.getChildCount(); i++) {
                View childAt = viewGroup.getChildAt(i);
                if (childAt instanceof RecyclerView) {
                    return childAt;
                }
                if (childAt instanceof ViewPager2) {
                    return childAt;
                }
                if (!(childAt instanceof ViewGroup)) {
                    continue;
                }
                recursionChildScrollView(childAt);
            }
        }
        return null;
    }

你可能感兴趣的:(android,javascript)