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

Flutter Maps动态标记onTap调用showModalBottomSheet报No MediaQuery错误咨询

错误原因

报错的核心是你调用showModalBottomSheet时传入的上下文不正确:_myContext是MyApp组件自身的上下文,而MediaQuery是MaterialApp内部才会初始化的能力,你的上下文处在MaterialApp的上层,自然找不到对应的MediaQuery祖先节点。

同时你还存在两个隐性问题:

  • 向markers集合添加新标记后没有调用setState,新标记不会触发页面重绘,无法显示在地图上
  • 数据库监听器的调用时机早于Firebase初始化完成的时机,可能出现空引用异常
解决方案

推荐采用组件拆分的方案,将地图相关逻辑拆分到MaterialApp的子组件中,确保使用的上下文位于MaterialApp子树内,可正常访问MediaQuery。

完整修改后的代码

import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:petrol_finder/data/PetrolStation.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const MyApp());
}

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

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  bool _initialized = false;
  bool _error = false;

  void initializeFlutterFire() async {
    try {
      await Firebase.initializeApp();
      setState(() {
        _initialized = true;
      });
    } catch(e) {
      setState(() {
        _error = true;
      });
    }
  }

  @override
  void initState() {
    initializeFlutterFire();
    super.initState();
  }

  Widget SomethingWentWrong() {
    return const ErrorWidget("Firebase初始化出错");
  }
  
  Widget Loading() {
    return const SizedBox.shrink();
  }

  @override
  Widget build(BuildContext context) {
    if(_error) {
      return SomethingWentWrong();
    }
    if (!_initialized) {
      return Loading();
    }
    return MaterialApp(
      home: const MapPage(),
    );
  }
}

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

  @override
  State<MapPage> createState() => _MapPageState();
}

class _MapPageState extends State<MapPage> {
  late GoogleMapController mapController;
  final petrolStationsDatabase = FirebaseDatabase(databaseURL:"[替换为你的数据库地址]").reference().child('petrolstations');
  final Set<Marker> markers = {};
  final LatLng _center = const LatLng(51.5074, -0.1272);

  void _onMapCreated(GoogleMapController controller) {
    mapController = controller;
  }

  @override
  void initState() {
    super.initState();
    _activateListeners();
  }

  void _activateListeners() {
    petrolStationsDatabase.onChildAdded.listen((event) {
      if(event.snapshot.key==null) {
        return;
      }
      final PetrolStation petrolStation = PetrolStation.fromJson(event.snapshot.value);
      final newMarker = Marker(
        markerId: MarkerId(event.snapshot.key!),
        position: LatLng(petrolStation.latitude, petrolStation.longitude),
        onTap: () {
          showModalBottomSheet<void>(
            context: context,
            builder: (context) {
              return Container(
                height: 200,
                color: Colors.amber,
                child: Center(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    mainAxisSize: MainAxisSize.min,
                    children: <Widget>[
                      const Text('Modal BottomSheet'),
                      ElevatedButton(
                        child: const Text('关闭底部弹窗'),
                        onPressed: () => Navigator.pop(context),
                      )
                    ],
                  ),
                ),
              );
            },
          );
        },
        icon: BitmapDescriptor.defaultMarker,
      );
      setState(() {
        markers.add(newMarker);
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('加油站查询'),
        backgroundColor: Colors.green[700],
      ),
      body: GoogleMap(
        onMapCreated: _onMapCreated,
        initialCameraPosition: CameraPosition(
          target: _center,
          zoom: 11.0,
        ),
        markers: markers,
      ),
    );
  }
}
改动说明
  • 拆分出独立的MapPage组件作为MaterialApp的主页,该组件的上下文位于MaterialApp子树内,可正常访问MediaQuery
  • 移除了原有的_myContext变量,直接使用MapPage的上下文调用showModalBottomSheet
  • 新增setState调用,添加marker后触发页面重绘,保证新标记能显示在地图上
  • 调整了数据库监听器的调用时机,确保Firebase初始化完成后才开启监听

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 02:18:04