百度地圖 `MapView` 內部攔截觸摸事件處理地圖拖動、縮放、旋轉。側滑菜單 (如 `DrawerLayout`、第三方 `SlidingMenu`) 同樣攔截邊緣滑動手勢打開菜單。**兩者都消費 `ACTION_MOVE` 事件,導致手勢被搶佔**,表現為:地圖無法拖動、或側滑菜單無法關閉/打開、或雙雙失效。
Android 事件分發機制:父 View 可通過 `onInterceptTouchEvent` 攔截事件。子 View 可調用 `parent.requestDisallowInterceptTouchEvent(true)` 要求父 View **不再攔截**,事件直接傳遞給子 View 處理。
public class CustomMapView extends MapView {
public CustomMapView(Context context) { super(context); }
public CustomMapView(Context context, AttributeSet attrs) { super(context, attrs); }
public CustomMapView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); }
@Override
public boolean onTouchEvent(MotionEvent event) {
// 關鍵:地圖處理觸摸時,請求父容器 (DrawerLayout) 不要攔截
getParent().requestDisallowInterceptTouchEvent(true);
return super.onTouchEvent(event);
}
}
佈局文件中替換原 `
DrawerLayout drawerLayout = findViewById(R.id.drawer_layout);
// 僅允許從屏幕最左邊 (邊緣) 滑動打開菜單,地圖區域內部滑動不觸發
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); // 默認鎖定
// 或在代碼中動態控制:
// 地圖區域觸摸時 -> drawerLayout.setDrawerLockMode(LOCK_MODE_LOCKED_CLOSED);
// 邊緣區域觸摸時 -> drawerLayout.setDrawerLockMode(LOCK_MODE_UNLOCKED);
若使用 `jfeinstein10/SlidingMenu` 等舊庫,需在其 `onTouchEvent` 或 `onInterceptTouchEvent` 中添加判斷:
`if (event.getX() > threshold && isMapTouched) return false;` 放行事件給地圖。
系統返回手勢 (邊緣滑動) 與側滑菜單衝突,需在 `Activity` 或 `DrawerLayout` 設置:
// Activity 中
getWindow().setSystemGestureExclusionRects(List.of(
new Rect(0, 0, 50, height), // 左邊緣 50dp 排除系統手勢
new Rect(width-50, 0, width, height) // 右邊緣
));
// 或 DrawerLayout.setSystemGestureExclusionRects() (API 29+)
核心衝突在於**觸摸事件攔截權爭奪**。最通用、侵入性最小的方案是**自定義 MapView 在 onTouchEvent 中調用 `requestDisallowInterceptTouchEvent(true)`**,強制聲明地圖正在處理觸摸,父容器 (DrawerLayout/SlidingMenu) 放行。配合 `DrawerLayout.LOCK_MODE_LOCKED_CLOSED` 限制菜單觸發區域,可完美共存。