Android中DrawerLayout+ViewPager滑動沖突的解決方法
DrawerLayout 是 Android 官方的側(cè)滑菜單控件,而 ViewPager 相信大家都很熟悉了。今天這里就講一下當(dāng)在 DrawerLayout 中嵌套 ViewPager 時,要如何解決滑動沖突的問題,效果如下:

首先,讓我們先來解決 DrawerLayout 和 ViewPager 的側(cè)滑事件沖突。當(dāng) DrawerLayout 中嵌套 ViewPager 時,側(cè)滑默認(rèn)是執(zhí)行 DrawerLayout 的側(cè)滑事件,因?yàn)?Android 的事件分發(fā)是從 外層 ViewGroup 向里逐級傳遞到 View 的。
所以會先執(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)掉了,無法傳到 ViewPager。
所以,我們像下面這樣,監(jiān)聽當(dāng) Drawer 打開時,將 DrawerLayout 設(shè)置為 LOCK_MODE_LOCKED_OPEN,這樣在 Drawer 被打開時,就能夠觸發(fā) 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) {
}
});
但是,當(dāng)側(cè)邊欄的 ViewPager 滑動到最后一頁,再向左滑動時,我們會希望能夠自然的關(guān)閉 Drawer。這就需要我們監(jiān)聽 ViewPager 的 PageChange 事件,當(dāng)滑動到最后一頁時,將 DrawerLayout 的 LockMode 設(shè)置回 LOCK_MODE_UNLOCKED。
這里,選擇在 DrawerFragment(也就是定義側(cè)邊欄的 Fragment) 中定義一個接口:
/**
* 監(jiān)聽側(cè)邊欄的頁面選擇。
*/
public interface OnDrawerPageChangeListener {
void onPageSelected(boolean isLast);
}
然后讓 MainActivity 實(shí)現(xiàn)這個接口:
@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è)滑事件沖突問題,剩下最后一個要處理的小問題就是在點(diǎn)擊空白區(qū)域時,也想要關(guān)閉側(cè)邊欄,這個就只需要:
// 點(diǎn)擊除開側(cè)邊欄的區(qū)域會收起側(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: 極光寶盒,一個基于 JPush 的輕便易用的通知框架。
以上就是本文的全部內(nèi)容,希望對大家的學(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抽屜效果的菜單編寫實(shí)例
- Android側(cè)滑菜單控件DrawerLayout使用詳解
- Android原生側(cè)滑控件DrawerLayout使用方法詳解
- Android組件之DrawerLayout實(shí)現(xiàn)抽屜菜單
- Android中DrawerLayout實(shí)現(xiàn)側(cè)滑菜單效果
- Android抽屜布局DrawerLayout的簡單使用
相關(guān)文章
Android中FloatingActionButton的顯示與隱藏示例
本篇文章主要介紹了Android中FloatingActionButton的顯示與隱藏示例,非常具有實(shí)用價值,需要的朋友可以參考下2017-10-10
Android模擬器安裝APP出現(xiàn)INSTALL_FAILED_NO_MATCHING_ABIS錯誤解決方案
這篇文章主要介紹了 Android模擬器安裝APP出現(xiàn)INSTALL_FAILED_NO_MATCHING_ABIS錯誤解決方案的相關(guān)資料,需要的朋友可以參考下2016-12-12
Android獲取手機(jī)配置信息具體實(shí)現(xiàn)代碼
下面為大家介紹下使用android獲取手機(jī)配置信息的具體過程,感興趣的朋友可以參考下哈,希望對你有所幫助2013-06-06
Android實(shí)現(xiàn)將應(yīng)用崩潰信息發(fā)送給開發(fā)者并重啟應(yīng)用的方法
這篇文章主要介紹了Android實(shí)現(xiàn)將應(yīng)用崩潰信息發(fā)送給開發(fā)者并重啟應(yīng)用的方法,涉及Android錯誤處理與應(yīng)用操作的相關(guān)技巧,需要的朋友可以參考下2016-03-03
事件是一種有用來收集用戶與應(yīng)用程序互動數(shù)據(jù)的互動組件,如按鍵或觸摸屏等放置事件,因?yàn)槊總€事件從Android框架維護(hù)事件隊(duì)列先入先出(FIFO)基礎(chǔ)上的隊(duì)列??梢栽诔绦蛑胁东@這些事件,按要求并采取適當(dāng)?shù)膭幼?/div> 2023-02-02
Android實(shí)現(xiàn)藍(lán)牙聊天功能
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)藍(lán)牙聊天功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-06-06
Android系統(tǒng)檢測程序內(nèi)存占用各種方法
這篇文章主要介紹了Android系統(tǒng)檢測程序內(nèi)存占用各種方法,本文講解了檢查系統(tǒng)總內(nèi)存、檢查某個程序的各類型內(nèi)存占用、檢查程序狀態(tài)、檢查程序各部分的內(nèi)存占用等內(nèi)容,需要的朋友可以參考下2015-03-03
Android TimeLine 時間節(jié)點(diǎn)軸的實(shí)現(xiàn)實(shí)例代碼
本篇文章主要介紹了Android TimeLine 時間節(jié)點(diǎn)軸的實(shí)現(xiàn)實(shí)例代碼,這里整理了詳細(xì)的代碼,有需要的小伙伴可以參考下。2017-03-03最新評論

