You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中flutter-mapbox-gl地图遮挡App Drawer侧边栏问题

问题原因

mapbox_gl 采用PlatformView嵌入原生地图组件,这类原生视图默认渲染优先级高于Flutter自身的Widget绘制层。你的代码中在MapControl、ViewView两层都额外嵌套了Scaffold,多层Scaffold冲突导致HomeView挂载的Drawer无法覆盖在原生地图上方,最终出现遮挡。

解决方案

方案1:移除冗余Scaffold(优先尝试,90%场景可直接修复)

整个路由栈只保留HomeView中的根Scaffold即可,删掉子页面多余的Scaffold嵌套:

  1. 修改map.dart,去掉MapboxMap外层包裹的Scaffold:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:mapbox_gl/mapbox_gl.dart';

import '../services/item.dart';

class MapControl extends StatefulWidget {
  const MapControl({Key? key}) : super(key: key);

  @override
  State<StatefulWidget> createState() => MapControlState();
}

class MapControlState extends State<MapControl> {
  final itemService = Get.find<ItemService>();
  MapboxMapController? mapController;

  _onMapCreated(MapboxMapController controller) {
    mapController = controller;
  }

  _onStyleLoadedCallback() {
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(
      content: const Text("Style loaded :)"),
      backgroundColor: Theme.of(context).primaryColor,
      duration: const Duration(seconds: 1),
    ));
  }

  @override
  Widget build(BuildContext context) {
    return MapboxMap(
      styleString: MapboxStyles.LIGHT,
      accessToken: 'xxxxxxxxxxxxxxxxx',
      onMapCreated: _onMapCreated,
      initialCameraPosition: const CameraPosition(target: LatLng(0.0, 0.0)),
      onStyleLoadedCallback: _onStyleLoadedCallback,
    );
  }
}
  1. 修改view_view.dart,去掉外层冗余Scaffold:
import 'package:flutter/material.dart';
import 'package:get/get.dart';

import '../../../common/calendar.dart';
import '../../../common/list.dart';
import '../../../common/map.dart';
import '../../../models/items.dart';
import '../controllers/view_controller.dart';

class ViewView extends GetView<ViewController> {
  const ViewView({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Obx(
      () => getView(controller.itemService.currentActiveViewItem.value)
    );
  }

  Widget getView(Item? viewItem) {
    switch (viewItem?.type?.name) {
      case "CalendarView":
        return const CalendarControl();
      case "ListView":
        return const ListControl();
      case "MapView":
        return const MapControl();
      default:
        return Container();
    }
  }
}

方案2:监听Drawer状态动态切换Map显示(方案1无效时使用)

如果移除冗余Scaffold后仍存在遮挡,可以在Drawer打开时临时隐藏Map组件,用占位组件替代,Drawer关闭后再恢复显示:

  1. 在HomeController中新增状态记录Drawer开合状态:
final RxBool isDrawerOpen = false.obs;
  1. 给HomeView的根Scaffold绑定GlobalKey,监听Drawer状态变化:
class HomeView extends GetView<HomeController> {
  final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();

  @override
  Widget build(BuildContext context) {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _scaffoldKey.currentState?.drawerController?.addListener(() {
        controller.isDrawerOpen.value = _scaffoldKey.currentState?.drawerController?.isOpen ?? false;
      });
    });

    return Obx(() => Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(
        title: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          mainAxisSize: MainAxisSize.min,
          children: [
            RealNetIcon(controller.itemService.currentItem.value),
            Text(controller.itemService.currentItem.value?.name ?? "RealNet")
          ],
        ),
        centerTitle: true,
      ),
      body: Navigator(
        key: Get.nestedKey(1),
        initialRoute: '/empty',
        onGenerateRoute: controller.onGenerateRoute,
      ),
      drawer: NavDrawer(),
      bottomNavigationBar: controller.itemService.currentViewItems.value.length >= 2
        ? BottomNavigationBar(
            type: BottomNavigationBarType.fixed,
            currentIndex: controller.itemService.currentActiveViewIndex.value,
            onTap: (value) {
              controller.itemService.updateActiveViewIndex(value);
            },
            items: [
              ...controller.itemService.currentViewItems.value.map((viewItem) => BottomNavigationBarItem(
                label: viewItem.name,
                icon: RealNetIcon(viewItem),
              )),
            ],
          )
        : null,
    ));
  }
}
  1. 修改ViewView中的getView逻辑,Drawer打开时替换Map为占位组件:
Widget getView(Item? viewItem) {
  if (controller.isDrawerOpen.value && viewItem?.type?.name == "MapView") {
    return Container(
      color: Colors.grey[100],
      alignment: Alignment.center,
      child: const CircularProgressIndicator(),
    );
  }
  switch (viewItem?.type?.name) {
    case "CalendarView":
      return const CalendarControl();
    case "ListView":
      return const ListControl();
    case "MapView":
      return const MapControl();
    default:
      return Container();
  }
}

方案3:Android端开启透明窗口配置

如果仅Android端存在遮挡,可修改MainActivity配置开启透明窗口,让原生视图层级低于Flutter绘制层:
打开android/app/src/main/kotlin/对应包名/MainActivity.kt,修改代码:

import io.flutter.embedding.android.FlutterActivity
import android.os.Build
import android.os.Bundle
import androidx.annotation.RequiresApi

class MainActivity: FlutterActivity() {
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        window.setBackgroundDrawableResource(android.R.color.transparent)
    }
}
复现环境信息
  • Flutter版本:3.0.1 stable(Windows平台)
  • 依赖版本:mapbox_gl: ^0.16.0, get: ^4.6.3
  • 问题截图:
    MapBox遮挡Drawer问题截图

内容的提问来源于stack exchange,提问作者Christine

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 03:21:40