首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

Android 側滑菜單 + ViewPager 左右滑動衝突解決:用 DrawerLayout + ViewPager 搭配 RequestDisallowInterceptTouchEvent

     編輯:程式設計疑難解答

需求:App 同時實現「左側滑出菜單」與「ViewPager 內容頁左右滑動切換」。核心衝突:**DrawerLayout 攔截觸摸事件導致 ViewPager 無法滑動**,或 ViewPager 消費事件導致側滑菜單打不開。本文給出 Google 官方推薦的協調方案。

衝突根因

  • DrawerLayout 內部 onInterceptTouchEvent 判斷邊緣滑動開啟菜單。
  • ViewPager 內部 onTouchEvent 處理頁面切換滑動。
  • 兩者都處理水平滑動,事件分發機制導致「搶佔」。

標準解決方案:DrawerLayout + ViewPager + RequestDisallowInterceptTouchEvent

佈局 XML

<androidx.drawerlayout.widget.DrawerLayout
    xmlns:android="https://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- 主內容:ViewPager -->
    <androidx.viewpager.widget.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!-- 側滑菜單 (左側) -->
    <com.google.android.material.navigation.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:menu="@menu/drawer_menu" />

</androidx.drawerlayout.widget.DrawerLayout>

關鍵 Java/Kotlin 代碼

viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
    @Override
    public void onPageScrollStateChanged(int state) {
        // 關鍵:ViewPager 開始拖動時,禁止 DrawerLayout 攔截
        if (state == ViewPager.SCROLL_STATE_DRAGGING) {
            drawerLayout.requestDisallowInterceptTouchEvent(true);
        } else {
            // 滑動結束/空閒時,恢復 DrawerLayout 攔截權限
            drawerLayout.requestDisallowInterceptTouchEvent(false);
        }
    }
    // onPageScrolled, onPageSelected 可留空
});

// 可選:邊緣滑動閾值優化(預設 20dp,可調大觸發側滑靈敏度)
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);

進階:自定義 ViewPager 內部自處理邊緣

public class SmartViewPager extends ViewPager {
    public SmartViewPager(Context context, AttributeSet attrs) { super(context, attrs); }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // 第一頁靠左邊緣、最後頁靠右邊緣,允許父容器攔截 (開啟側滑/右側菜單)
        if (getCurrentItem() == 0 && ev.getX() < getWidth() * 0.1f) return false;
        if (getCurrentItem() == getAdapter().getCount() - 1 && ev.getX() > getWidth() * 0.9f) return false;
        return super.onInterceptTouchEvent(ev);
    }
}

參考資源

避坑清單

  1. 不要在 onTouchEvent 返回 false 破壞事件鏈。
  2. requestDisallowInterceptTouchEvent(true) 必須在 SCROLL_STATE_DRAGGING 時調用,SETTLING/IDLE 時釋放。
  3. 若用 FragmentStatePagerAdapter,注意 Fragment 生命週期與觸摸事件的關係。
  4. 測試場景:第一頁左滑開菜單、最後頁右滑(如有右側菜單)、中間頁正常切換、快速滑動邊界情況。

掌握 requestDisallowInterceptTouchEvent 這個「事件分發協調開關」,側滑菜單與 ViewPager 完美共存。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved