最近在项目中用到viewpager嵌套viewpager,但是就以普通的方式,在Fragment中的viewpager在滑动完之后,就会触发外部的viewpager的滑动,遇到这个问题之后,在网上搜寻,类似的帖子很多,但是有些效果不是很好,但是还是找到一种,今天在这里记录一下.

先看看最后完成的效果,以免耽误大家的时间。

接下来就是解决的方法了。
说到滑动冲突,第一个向导的就是事件传递上做做手脚,所以我们先想想,冲突产生的原因。

在最里面的viewpager滑动到最左或者最右边的时候,外边的viewpager就会拦截滑动事件,从而滑动到下一个item。

既然viewpager走了拦截事件,那就看onIntercepterTouchEvent方法的代码可以知道,在MotionEvent.ACTION_MOVE中会调用

 if (dx != 0 && !isGutterDrag(mLastMotionX, dx)                        && canScroll(this, false, (int) dx, (int) x, (int) y)) {                    // Nested view has scrollable area under this point. Let it be handled there.                    mLastMotionX = x;                    mLastMotionY = y;                    mIsUnableToDrag = true;                    return false;                }

其中有一个canScroll方法,通过他的名字就可以看出,这个方法是用来判断控件的子控件是否可以滑动,

/**     * Tests scrollability within child views of v given a delta of dx.     *     * @param v View to test for horizontal scrollability     * @param checkV Whether the view v passed should itself be checked for scrollability (true),     *               or just its children (false).     * @param dx Delta scrolled in pixels     * @param x X coordinate of the active touch point     * @param y Y coordinate of the active touch point     * @return true if child views of v can be scrolled by delta of dx.     */    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {        if (v instanceof ViewGroup) {            final ViewGroup group = (ViewGroup) v;            final int scrollX = v.getScrollX();            final int scrollY = v.getScrollY();            final int count = group.getChildCount();            // Count backwards - let topmost views consume scroll distance first.            for (int i = count - 1; i >= 0; i--) {                // TODO: Add versioned support here for transformed views.                // This will not work for transformed views in Honeycomb+                final View child = group.getChildAt(i);                if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight()                        && y + scrollY >= child.getTop() && y + scrollY < child.getBottom()                        && canScroll(child, true, dx, x + scrollX - child.getLeft(),                                y + scrollY - child.getTop())) {                    return true;                }            }        }        return checkV && ViewCompat.canScrollHorizontally(v, -dx);    }

用递归的方式找到底层的View,通过判断子viewpager在滑动到最左或最右时,canScroll方法会饭后false,导致最后的结果为ViewPager拦截了事件.

同时,这个子视图不单是viewpager,也可以是其他可滑动的控件例如Recyclerview。
在本案例中,解决的方法是自定义外部的viewpager。

public class ParentViewPager extends ViewPager {    public ParentViewPager(Context context) {        super(context);    }    public ParentViewPager(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {    //解决关键在这里        if (v != this && v instanceof ViewPager) {            return true;        }        return super.canScroll(v, checkV, dx, x, y);    }}

如果大兄弟你嵌套的是recyclerview,也可以这么写。

 @Override    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {        return super.canScroll(v, checkV, dx, x, y)||(v instanceof RecyclerView)||(v instanceof ViewPager);    }

自己测试过了,复制可以直接使用。

更多相关文章

  1. 高德地图 android api 实现自动定位
  2. 从源码剖析PopupWindow 兼容Android(安卓)6.0以上版本点击外部不
  3. App启动流程-源码分析
  4. AndroidStudio使用GreenDao的方法
  5. android EditText的setCompoundDrawables用法
  6. Android(安卓)消息机制学习
  7. Android---Android下嵌入式数据库SqlLite使用方法
  8. Android(安卓)提交数据到服务器的四种方法
  9. Android实现定时执行某个任务

随机推荐

  1. 3: Zabbix5.0自动发现磁盘目录监控
  2. 这应该是堪称完美的“Android Framework
  3. telnet登录Linux上报Login incorrect
  4. Java锁机制了解一下
  5. 使用docker compose 安装zookeeper、kafk
  6. 文章目录导航
  7. Android(安卓)-- Vold机制简要分析
  8. Thread源码剖析
  9. ConcurrentHashMap基于JDK1.8源码剖析
  10. 四种常量的解释