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;
}
});

到这里就大功告成啦!

作者:Hevin - 极光开发者

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

知乎专栏:极光日报

Android 中 DrawerLayout + ViewPager 怎么解决滑动冲突?的更多相关文章

  1. 解决ScrollView嵌套ViewPager出现的滑动冲突问题

    /**       *         解决ScrollView嵌套ViewPager出现的滑动冲突问题       */       public class ScrollView1 extends ...

  2. Android:使用ViewPager实现左右滑动切换图片 (简单版)

    ViewPager,它是google SDk中自带的一个附加包的一个类, 可以使视图滑动. 步骤: 1.引入android-support-v4.jar包,在主布局里加入 <android.su ...

  3. Android:使用ViewPager实现左右滑动切换图片(图上有点点)

    在以下实例的基础上加上点点 Android:使用ViewPager实现左右滑动切换图片 (简单版) 效果预览: 因为要把点点放图片上,所以修改布局为相对布局: <?xml version=&qu ...

  4. Android中Touch事件分析--解决HorizontalScrollView滑动和按钮事件触发问题

    之前写过关于HorizontalScrollView滑动和按钮事件触发问题,但是不能所有的情况,最近几天一直在想这个问题,今天有一个比较好的解决思路,最终应用在项目里面效果也很好,首先说明一下功能: ...

  5. 【Android 应用开发】Android中使用ViewPager制作广告栏效果 - 解决ViewPager占满全屏页面适配问题

    . 参考界面 : 携程app首页的广告栏, 使用ViewPager实现        自制页面效果图 : 源码下载地址: http://download.csdn.net/detail/han1202 ...

  6. Android中使用ViewPager制作广告栏效果 - 解决ViewPager占满全屏页面适配问题

    . 参考界面 : 携程app首页的广告栏, 使用ViewPager实现        自制页面效果图 : 源码下载地址: http://download.csdn.net/detail/han1202 ...

  7. Android中使用ViewPager实现屏幕页面切换和页面切换效果

    之前关于如何实现屏幕页面切换,写过一篇博文<Android中使用ViewFlipper实现屏幕切换>,相比ViewFlipper,ViewPager更适用复杂的视图切换,而且Viewpag ...

  8. 《Android View 的事件分发和滑动冲突》 —预习资料

    1. 阅读书籍<Android开发艺术探索>第三章 2. 提前阅读如下技术文章: http://blog.csdn.net/singwhatiwanna/article/details/3 ...

  9. Android中Fragment+ViewPager的配合使用

    官方推荐 ViewPager与Fragment一起使用,可以更加方便的管理每个Page的生命周期,这里有标准的适配器实现用于ViewPager和Fragment,涵盖最常见的用例.FragmentPa ...

随机推荐

  1. Codeforces 712D DP

    题意:有2个人玩游戏,他们都有个初始值a和b, 游戏进行t轮, 每次可以选择加上一个[-k, +k]之间的数字,问有多少种方案a的和严格大于b的和. 思路:如果不考虑多于这个条件,只是询问有多少种方案 ...

  2. Linux安装MySQL全过程

    操作系统:CentOS 7.2  64位 mySQL版本:mysql-5.6.35 安装过程: (1)首先从mysql官网下载 MySQL Community Server 安装包. 选择对应的版本( ...

  3. leetcode BFS解题思路

    Word Ladder 思路一:单向bfs, 使用visited数组记录哪些已经访问过了, 访问过的就不允许再次入队, 同时这里想到的是使用26个英文字母,枚举可能的取值, 类似brute force ...

  4. T-sql GroupBy语句常见问题处理

    1.问题描述 现在有一张course表(含课程编号和名称)和一张sc表(含学生学号,选修课程的编号以及考试成绩),如下:现在想要查询所有课程编号.对应的课程名称以及选修该课程的所有学生的平均成绩.一开 ...

  5. [C++] Variable/Hex conversion

    程序编译链接原理预处理:.c -> .i gcc -E hello.c -o hello.i 编译:.i / .c -> .sgcc -S hello.i -o hello.s 汇编:.s ...

  6. code1052 地鼠游戏

    贪心算法,从后往前 来自codevs的题解: 我的纠结思考过程:如果每一秒都没有重复的地鼠出现 那么肯定是一个一个挨着打如果有重复的地鼠 那么要考虑打那个更优 当然是选分值最大的 单纯这样想很合理 但 ...

  7. hbase java api样例(版本1.3.1,新API)

    hbase版本:1.3.1 目的:HBase新API的使用方法. 尝试并验证了如下几种java api的使用方法. 1.创建表 2.创建表(预分区) 3.单条插入 4.批量插入 5.批量插入(客户端缓 ...

  8. python 的输入和输出

    内置函数:raw_inpurt('place input') print getpass  隐藏输入密码 import getpass pwd = getpass.getpass("> ...

  9. Auth模块

    文本目录 1 扩展默认的auth_user表 2 auth模块是什么 3 auth模块的常用方法 1 扩展默认的auth_user 表 在开始写项目之前,我们要创建表,同事内置的认证系统又很好用,但是 ...

  10. springdata -----操作ES

    一:配置springdata-Es elasticseach-JPA.xml <?xml version="1.0" encoding="UTF-8"?& ...