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基础路由定义与参数传递规则【详解】
如何在橙子建站上传落地页?操作指南详解
上一篇:linux操作系统的搭建
上一篇:linux操作系统的搭建

