Android中DrawerLayout+ViewPager滑動(dòng)沖突的解決方法
DrawerLayout 是 Android 官方的側(cè)滑菜單控件,而 ViewPager 相信大家都很熟悉了。今天這里就講一下當(dāng)在 DrawerLayout 中嵌套 ViewPager 時(shí),要如何解決滑動(dòng)沖突的問(wèn)題,效果如下:
首先,讓我們先來(lái)解決 DrawerLayout 和 ViewPager 的側(cè)滑事件沖突。當(dāng) DrawerLayout 中嵌套 ViewPager 時(shí),側(cè)滑默認(rèn)是執(zhí)行 DrawerLayout 的側(cè)滑事件,因?yàn)?Android 的事件分發(fā)是從 外層 ViewGroup 向里逐級(jí)傳遞到 View 的。
所以會(huì)先執(zhí)行 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,意味著點(diǎn)擊事件在 DrawerLayout 就被消費(fèi)掉了,無(wú)法傳到 ViewPager。
所以,我們像下面這樣,監(jiān)聽(tīng)當(dāng) Drawer 打開(kāi)時(shí),將 DrawerLayout 設(shè)置為 LOCK_MODE_LOCKED_OPEN,這樣在 Drawer 被打開(kāi)時(shí),就能夠觸發(fā) ViewPager 的滑動(dòng)事件了。
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) { } });
但是,當(dāng)側(cè)邊欄的 ViewPager 滑動(dòng)到最后一頁(yè),再向左滑動(dòng)時(shí),我們會(huì)希望能夠自然的關(guān)閉 Drawer。這就需要我們監(jiān)聽(tīng) ViewPager 的 PageChange 事件,當(dāng)滑動(dòng)到最后一頁(yè)時(shí),將 DrawerLayout 的 LockMode 設(shè)置回 LOCK_MODE_UNLOCKED。
這里,選擇在 DrawerFragment(也就是定義側(cè)邊欄的 Fragment) 中定義一個(gè)接口:
/** * 監(jiān)聽(tīng)側(cè)邊欄的頁(yè)面選擇。 */ public interface OnDrawerPageChangeListener { void onPageSelected(boolean isLast); }
然后讓 MainActivity 實(shí)現(xiàn)這個(gè)接口:
@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 的側(cè)滑事件沖突問(wèn)題,剩下最后一個(gè)要處理的小問(wèn)題就是在點(diǎn)擊空白區(qū)域時(shí),也想要關(guān)閉側(cè)邊欄,這個(gè)就只需要:
// 點(diǎn)擊除開(kāi)側(cè)邊欄的區(qū)域會(huì)收起側(cè)邊欄。 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; } });
到這里就大功告成啦!完整的代碼可以參考項(xiàng)目:jpush/jbox: 極光寶盒,一個(gè)基于 JPush 的輕便易用的通知框架。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android實(shí)現(xiàn)右邊抽屜Drawerlayout效果
- Android側(cè)滑菜單之DrawerLayout用法詳解
- Android DrawerLayout實(shí)現(xiàn)側(cè)拉菜單功能
- Android使用DrawerLayout實(shí)現(xiàn)仿QQ雙向側(cè)滑菜單
- Android App中DrawerLayout抽屜效果的菜單編寫(xiě)實(shí)例
- Android側(cè)滑菜單控件DrawerLayout使用詳解
- Android原生側(cè)滑控件DrawerLayout使用方法詳解
- Android組件之DrawerLayout實(shí)現(xiàn)抽屜菜單
- Android中DrawerLayout實(shí)現(xiàn)側(cè)滑菜單效果
- Android抽屜布局DrawerLayout的簡(jiǎn)單使用
相關(guān)文章
Android中FloatingActionButton的顯示與隱藏示例
本篇文章主要介紹了Android中FloatingActionButton的顯示與隱藏示例,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-10-10Android模擬器安裝APP出現(xiàn)INSTALL_FAILED_NO_MATCHING_ABIS錯(cuò)誤解決方案
這篇文章主要介紹了 Android模擬器安裝APP出現(xiàn)INSTALL_FAILED_NO_MATCHING_ABIS錯(cuò)誤解決方案的相關(guān)資料,需要的朋友可以參考下2016-12-12Android獲取手機(jī)配置信息具體實(shí)現(xiàn)代碼
下面為大家介紹下使用android獲取手機(jī)配置信息的具體過(guò)程,感興趣的朋友可以參考下哈,希望對(duì)你有所幫助2013-06-06Android實(shí)現(xiàn)將應(yīng)用崩潰信息發(fā)送給開(kāi)發(fā)者并重啟應(yīng)用的方法
這篇文章主要介紹了Android實(shí)現(xiàn)將應(yīng)用崩潰信息發(fā)送給開(kāi)發(fā)者并重啟應(yīng)用的方法,涉及Android錯(cuò)誤處理與應(yīng)用操作的相關(guān)技巧,需要的朋友可以參考下2016-03-03Android實(shí)現(xiàn)藍(lán)牙聊天功能
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)藍(lán)牙聊天功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06Android系統(tǒng)檢測(cè)程序內(nèi)存占用各種方法
這篇文章主要介紹了Android系統(tǒng)檢測(cè)程序內(nèi)存占用各種方法,本文講解了檢查系統(tǒng)總內(nèi)存、檢查某個(gè)程序的各類型內(nèi)存占用、檢查程序狀態(tài)、檢查程序各部分的內(nèi)存占用等內(nèi)容,需要的朋友可以參考下2015-03-03Android TimeLine 時(shí)間節(jié)點(diǎn)軸的實(shí)現(xiàn)實(shí)例代碼
本篇文章主要介紹了Android TimeLine 時(shí)間節(jié)點(diǎn)軸的實(shí)現(xiàn)實(shí)例代碼,這里整理了詳細(xì)的代碼,有需要的小伙伴可以參考下。2017-03-03