DrawerLayout 是 Android 官方的侧滑菜单控件,而 ViewPager 相信大家都很熟悉了。今天这里就讲一下当在 DrawerLayout 中嵌套 ViewPager 时,要如何解决滑动冲突的问题,效果如下: 效果图

首先,让我们先来解决 DrawerLayout 和 ViewPager 的侧滑事件冲突。当 DrawerLayout 中嵌套 ViewPager 时,侧滑默认是执行 DrawerLayout 的侧滑事件,因为 Android 的事件分发是从 外层 ViewGroup 向里逐级传递到 View 的。

所以会先执行 DrawerLayout 的 onTouchEvent 方法:

@Overridepublic boolean onTouchEvent(MotionEvent ev) {    mLeftDragger.processTouchEvent(ev);     mRightDragger.processTouchEvent(ev);     final int action = ev.getAction(); boolean wantTouchEvents = true;     switch (action & MotionEventCompat.ACTION_MASK) {         case MotionEvent.ACTION_DOWN: {             final float x = ev.getX();             final float y = ev.getY();             mInitialMotionX = x;             mInitialMotionY = y;             mDisallowInterceptRequested = false;             mChildrenCanceledTouch = false;             break;         }         case MotionEvent.ACTION_UP: {             final float x = ev.getX();             final float y = ev.getY();             boolean peekingOnly = true;            final View touchedView = mLeftDragger.findTopChildUnder((int) x, (int) y);             if (touchedView != null && isContentView(touchedView)) {                 final float dx = x - mInitialMotionX;                 final float dy = y - mInitialMotionY;                 final int slop = mLeftDragger.getTouchSlop();                 if (dx * dx + dy * dy < slop * slop) {                     // Taps close a dimmed open drawer but only if it isn't locked open.                     final View openDrawer = findOpenDrawer();                     if (openDrawer != null) {                         peekingOnly = getDrawerLockMode(openDrawer) == LOCK_MODE_LOCKED_OPEN;                     }                 }              }             closeDrawers(peekingOnly);             mDisallowInterceptRequested = false;             break;         }         case MotionEvent.ACTION_CANCEL: {             closeDrawers(true);             mDisallowInterceptRequested = false;            mChildrenCanceledTouch = false; break;         }     }     return wantTouchEvents;}

可以看到在最后始终返回 wantTouchEvents,也就是返回 true,意味着点击事件在 DrawerLayout 就被消费掉了,无法传到 ViewPager。

所以,我们像下面这样,监听当 Drawer 打开时,将 DrawerLayout 设置为 LOCK_MODE_LOCKED_OPEN,这样在 Drawer 被打开时,就能够触发 ViewPager 的滑动事件了。

mDrawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() {   @Override   public void onDrawerSlide(View drawerView, float slideOffset) {   }   @Override   public void onDrawerOpened(View drawerView) {    mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN);  }   @Override public void onDrawerClosed(View drawerView) {    mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);   }   @Override public void onDrawerStateChanged(int newState) {   }});

但是,当侧边栏的 ViewPager 滑动到最后一页,再向左滑动时,我们会希望能够自然的关闭 Drawer。这就需要我们监听 ViewPager 的 PageChange 事件,当滑动到最后一页时,将 DrawerLayout 的 LockMode 设置回 LOCK_MODE_UNLOCKED。

这里,选择在 DrawerFragment (也就是定义侧边栏的 Fragment ) 中定义一个接口:

/** * 监听侧边栏的页面选择。 */public interface OnDrawerPageChangeListener {   void onPageSelected(boolean isLast);}

然后让 MainActivity 实现这个接口:

@Overridepublic void onPageSelected(boolean isLast) {   if (isLast) {     mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);  } else if (mDrawerLayout.getDrawerLockMode(GravityCompat.START) == DrawerLayout.LOCK_MODE_UNLOCKED) {    mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN);   }}

再在 DrawerFragment 中 ViewPager 的 PageChange 事件中使用:

final OnDrawerPageChangeListener drawerPageChangeListener = (OnDrawerPageChangeListener) getActivity();mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {   @Override   public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {  }   @Override   public void onPageSelected(int position) {     if (position == fragmentList.size() - 1) {       drawerPageChangeListener.onPageSelected(true);     } else {       drawerPageChangeListener.onPageSelected(false);     }   }   @Override   public void onPageScrollStateChanged(int state) {   }});

这样我们就解决了 DrawerLayout 和 ViewPager 的侧滑事件冲突问题,剩下最后一个要处理的小问题就是在点击空白区域时,也想要关闭侧边栏,这个就只需要:

// 点击除开侧边栏的区域会收起侧边栏。mDrawerLayout.setOnTouchListener(new View.OnTouchListener() {   @Override   public boolean onTouch(View v, MotionEvent event) {     switch (event.getAction()) {       case MotionEvent.ACTION_DOWN:         mDrawerLayout.closeDrawers();        break;    }     return false;   }});

到这里就大功告成啦!

作者:Hevin - 极光( JPush 为极光开发者团队账号,欢迎关注)

原文:Android 中 DrawerLayout + ViewPager 怎么解决滑动冲突?

知乎专栏:极光日报

更多相关文章

  1. Android关于Activity屏蔽/拦截Home键
  2. android点击事件穿透
  3. android开发技巧精髓十
  4. Message Android的享元模式
  5. Android压力测试快速入门教程(图解)——Monkey工具
  6. Android基础——通过activity和XML绑定实现按钮点击事件
  7. android中file的使用实例
  8. android 使用XmlResourceParser 解析XML
  9. Android事件分发机制详解(二)

随机推荐

  1. 【Android(安卓)初学】9、Activity生命周
  2. Android(安卓)Vibrator开启振动功能
  3. android计数器——基础编
  4. android 线程更新view及数据传送
  5. OnConfigurationChanged 配置变化。 屏幕
  6. ActivityLaunchMode
  7. Android中的选项菜单(OptionMenu)使用案例
  8. Android(安卓)获取Ip
  9. Android(安卓)studio中给Button添加点击
  10. mac 无法连接android手机进行调试 解决方