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

发布时间 - 2026-01-11 01:50:38    点击率:

DrawerLayout 是 Android 官方的侧滑菜单控件,而 ViewPager 相信大家都很熟悉了。今天这里就讲一下当在 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 的轻便易用的通知框架。

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


# Android  # DrawerLayout  # ViewPager  # 滑动冲突  # Android实现右边抽屉Drawerlayout效果  # Android侧滑菜单之DrawerLayout用法详解  # Android DrawerLayout实现侧拉菜单功能  # Android使用DrawerLayout实现仿QQ双向侧滑菜单  # Android App中DrawerLayout抽屉效果的菜单编写实例  # Android侧滑菜单控件DrawerLayout使用详解  # Android原生侧滑控件DrawerLayout使用方法详解  # Android组件之DrawerLayout实现抽屉菜单  # Android中DrawerLayout实现侧滑菜单效果  # Android抽屉布局DrawerLayout的简单使用  # 大家都  # 让我们  # 是从  # 这就  # 可以看到  # 大功告成  # 掉了  # 只需要  # 设置为  # 易用  # 如何解决  # 先来  # 很熟悉  # 大家多多  # 会先  # 再向  # 宝盒  # 解决了  # 就是在  # 事件中 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 极客网站有哪些,DoNews、36氪、爱范儿、虎嗅、雷锋网、极客公园这些互联网媒体网站有什么差异?  Laravel如何生成和使用数据填充?(Seeder和Factory示例)  网站制作软件有哪些,制图软件有哪些?  Laravel如何发送邮件_Laravel Mailables构建与发送邮件的简明教程  详解jQuery停止动画——stop()方法的使用  矢量图网站制作软件,用千图网的一张矢量图做公司app首页,该网站并未说明版权等问题,这样做算不算侵权?应该如何解决?  为什么php本地部署后css不生效_静态资源加载失败修复技巧【技巧】  大型企业网站制作流程,做网站需要注册公司吗?  弹幕视频网站制作教程下载,弹幕视频网站是什么意思?  如何在万网自助建站平台快速创建网站?  jimdo怎样用html5做选项卡_jimdo选项卡html5实现与切换效果【指南】  Laravel怎么导出Excel文件_Laravel Excel插件使用教程  Linux网络带宽限制_tc配置实践解析【教程】  黑客如何通过漏洞一步步攻陷网站服务器?  高防网站服务器:DDoS防御与BGP线路的AI智能防护方案  Win11怎么更改系统语言为中文_Windows11安装语言包并设为显示语言  如何在万网利用已有域名快速建站?  企业在线网站设计制作流程,想建设一个属于自己的企业网站,该如何去做?  Laravel如何实现用户密码重置功能?(完整流程代码)  Laravel中DTO是什么概念_在Laravel项目中使用数据传输对象(DTO)  高端建站如何打造兼具美学与转化的品牌官网?  如何使用 jQuery 正确渲染 Instagram 风格的标签列表  JavaScript如何实现倒计时_时间函数如何精确控制  如何为不同团队 ID 动态生成多个独立按钮  如何快速建站并高效导出源代码?  零服务器AI建站解决方案:快速部署与云端平台低成本实践  Laravel怎么上传文件_Laravel图片上传及存储配置  英语简历制作免费网站推荐,如何将简历翻译成英文?  phpredis提高消息队列的实时性方法(推荐)  如何获取PHP WAP自助建站系统源码?  高性价比服务器租赁——企业级配置与24小时运维服务  laravel怎么用DB facade执行原生SQL查询_laravel DB facade原生SQL执行方法  Laravel怎么连接多个数据库_Laravel多数据库连接配置  如何快速完成中国万网建站详细流程?  如何在HTML表单中获取用户输入并结合JavaScript动态控制复利计算循环  海南网站制作公司有哪些,海口网是哪家的?  PHP 500报错的快速解决方法  如何自定义safari浏览器工具栏?个性化设置safari浏览器界面教程【技巧】  如何在IIS中新建站点并配置端口与物理路径?  如何用已有域名快速搭建网站?  Laravel Eloquent:优雅地将关联模型字段扁平化到主模型中  Laravel Asset编译怎么配置_Laravel Vite前端构建工具使用  Laravel如何实现用户角色和权限系统_Laravel角色权限管理机制  Laravel如何实现多级无限分类_Laravel递归模型关联与树状数据输出【方法】  Claude怎样写约束型提示词_Claude约束提示词写法【教程】  Python制作简易注册登录系统  打开php文件提示内存不足_怎么调整php内存限制【解决方案】  PHP正则匹配日期和时间(时间戳转换)的实例代码  Laravel路由Route怎么设置_Laravel基础路由定义与参数传递规则【详解】  如何在橙子建站上传落地页?操作指南详解