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

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 的轻便易用的通知框架。

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

时间: 2024-09-03 20:10:51

Android中DrawerLayout+ViewPager滑动冲突的解决方法的相关文章

android中view手势滑动冲突的解决方法_Android

Android手势事件的冲突跟点击事件的分发过程息息相关,由三个重要的方法来共同完成,分别是:dispatchTouchEvent.onInterceptTouchEvent和onTouchEvent. public boolean dispatchTouchEvent(MotionEvent ev) 这个方法用来进行事件的分发.如果事件传递到view,那么这个方法一定会被调用,返回结果受当前View的onTouchEvent和下级View的dispatchTouchEvent方法的影响,表示是

PHP针对常规模板引擎中与CSS/JSON冲突的解决方法_php技巧

本文实例讲述了PHP针对常规模板引擎中与CSS/JSON冲突的解决方法,有一定的实用价值,具体分析如下: 本文主要针对对象为Smarty与Dwoo 在Smarty中经常会出现和CSS/JS的语法存在冲突的情况,因为二者都需要使用大括号{}.虽然可以改Smarty的界定符,但你在一个现存系统中,去修改所有相关代码,是不划算的.解决方法如下: 1. 避免同时出现 通过外部引用的方式避免.问题是避无所避.所以这种情况只适合少量简单的情况. 2. 修改Smarty界定符 3.可以使用Smarty的lit

Android中ScrollView嵌套GridView显示不全解决方法

Android中ScrollView嵌套GridView显示不全解决方法 由于ScrollView和GridView这两款控件都自带滚动条,一起使用GridView会显示不全 解决方法:自定义gridview 感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

Android中RecyclerView嵌套滑动冲突解决的代码片段_Android

在纵向RecyclerView嵌套横向RecyclerView时,如果纵向RecyclerView有下拉刷新功能,那么内部的横向RecyclerView的横向滑动体验会很差.(只有纯横向滑动时,才能滑动内部的横向RecyclerView,否则滑动事件就会影响到下拉刷新),添加拦截判断. public class MySwipeRefreshLayout extends SwipeRefreshLayout { private boolean mIsVpDragger; private final

Android嵌套滑动冲突的解决方法

android在嵌套滑动的时候会产生滑动冲突.之前我也碰到,但是以前的笔记本丢失了,所以只能重新再写一章. 一.会产生滑动冲突的情况 那么什么时候会产生滑动冲突呢?比如你有个activity,activity的上半部分是一个布局,下半部分是一个可滑动控件(RecyclerView.ListView等),或者下半部分是个viewpager,里面的fragment布局是一个可滑动控件,这样的页面就会产生滑动冲突. 二.以前的做法 虽然我以前的笔记丢失了,但是当时的解决问题的思路我依然记得. (1)重

浅谈Android View滑动冲突的解决方法

引言 这一篇文章我们就通过介绍滑动冲突的规则和一个实例来更加深入的学习View的事件分发机制. 1.外部滑动方向和内部滑动方向不一致 考虑这样一种场景,开发中我们经常使用ViewPager和Fragment配合使用所组成的页面滑动效果,很多主流的应用都会使用这样的效果.在这种效果中,可以使用左右滑动来切换界面,而每一个界面里面往往又都是ListView这样的控件.本来这种情况是存在滑动冲突的,只是ViewPager内部处理了这种滑动冲突.如果我们不使用ViewPager而是使用ScrollVie

ScrollView嵌套ListView滑动冲突的解决方法_Android

ScrollView和ListView这两个控件想必大家都不会陌生,但是这两者嵌套使用的时候就会出现麻烦.比如,我们如果想在ListView下面添加其他的布局或者控件,然后想让它们作为一个整体都可以滑动的话,最常想到的就是用一个ScrollView把它们包裹起来.想法似乎很美好,但是现实就有点残酷了.我们可以写一个小例子体验一下. 首先创建一个Activity,在它的布局文件上放置一个ListView: <?xml version="1.0" encoding="utf

PHP中__autoload与smarty3冲突的解决方法

今天更新了smarty到3.0,结果发现项目中的__autoload()不能用了, 作为一个刚学习PHP 的菜鸟新手,搞了半天才明白问题出在它俩的冲突上,郁闷了好几天.后通过查看,Smarty3.0 中的SMARTY2_BC_NOTES文件,得 知Smarty3.0跟php的__autoload()有冲突: ------------------------------ == Autoloader == Smarty 3 does register its own autoloader with

Android中RecyclerView嵌套滑动冲突解决的代码片段

在纵向RecyclerView嵌套横向RecyclerView时,如果纵向RecyclerView有下拉刷新功能,那么内部的横向RecyclerView的横向滑动体验会很差.(只有纯横向滑动时,才能滑动内部的横向RecyclerView,否则滑动事件就会影响到下拉刷新),添加拦截判断. public class MySwipeRefreshLayout extends SwipeRefreshLayout { private boolean mIsVpDragger; private final