Android中DrawerLayout+ViewPager滑动冲突的解决方法

发布时间:2020-10-07 02:52:52 作者:Hevin丶
来源:脚本之家 阅读:196

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

Android中DrawerLayout+ViewPager滑动冲突的解决方法

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

@Override
public 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 实现这个接口:

@Override
public 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; 
 }
});

到这里就大功告成啦!完整的代码可以参考项目:jpush/jbox: 极光宝盒,一个基于 JPush 的轻便易用的通知框架。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持亿速云。

推荐阅读:
  1. 如何在Android中解决View滑动冲突
  2. Android中怎么解决嵌套滑动冲突

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

android drawerlayout viewpager

上一篇:Python 在 VSCode 中使用 IPython Kernel 的方法详解

下一篇:Angular项目中$scope.$apply()方法的使用详解

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》