ViewPager+ViewPager就不会产生冲突,那是应为,官方ViewPager帮我们已经处理过,但是
ViewPager2,并未帮我们处理。
然而我们通过源码发现:getParent().requestDisallowInterceptTouchEvent(boolean)是决定是否拦截事件
<com.zsy.rjgc.viewpager.NestedScrollableHost
android:layout_width="match_parent"
android:id="@+id/t_n"
android:layout_height="match_parent"
android:background="@color/teal_700">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewpager_t"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</com.zsy.rjgc.viewpager.NestedScrollableHost>
官方通过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<View> 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;
}