Flutter Map开发报错:MapController不存在onReady getter
问题
使用flutter_map开发Flutter地图应用,需求是设备就绪后获取定位并将地图移动到该位置,但代码报错:
The getter 'onReady' isn't defined for the type 'MapController'.
相关代码
main.dart
import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:spot_the_bird/bloc/location_cubit.dart'; import 'package:spot_the_bird/screens/map_screen.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MultiBlocProvider( providers: [ BlocProvider<LocationCubit>( create: (context) => LocationCubit()..getLocation(), ), ], child: MaterialApp( title: 'Flutter Demo', theme: ThemeData( appBarTheme: const AppBarTheme(backgroundColor: Color(0xff1746A2)), colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.deepOrange), ), initialRoute: "/", routes: { "/": (context) => MapScreen(), }, ), ); } }
MapScreen
import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:latlong2/latlong.dart'; import 'package:spot_the_bird/bloc/location_cubit.dart'; class MapScreen extends StatelessWidget { MapScreen({super.key}); final MapController _mapController = MapController(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), body: BlocListener<LocationCubit, LocationState>( listener: (prevState, currState) { if (currState is LocationError) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(currState.message), duration: const Duration(seconds: 3), backgroundColor: Theme.of(context).errorColor, ), ); } if (currState is LocationLoaded) { _mapController.onReady.then((value) => _mapController.move( LatLng(currState.latitude, currState.longitude), 15)); // 此处报错 } }, child: FlutterMap( mapController: _mapController, options: MapOptions( center: LatLng(51.509364, -0.128928), zoom: 15, minZoom: 4, ), children: [ TileLayer( urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', subdomains: const ['a', 'b', 'c'], retinaMode: true, ) ], ), ), floatingActionButton: FloatingActionButton( onPressed: () { context.read<LocationCubit>().getLocation(); }, child: const Icon(Icons.navigation_outlined), ), ); } }
Location Cubit
import 'package:equatable/equatable.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:geolocator/geolocator.dart'; part 'location_state.dart'; class LocationCubit extends Cubit<LocationState> { LocationCubit() : super(const LocationInitial()); Future<void> getLocation() async { LocationPermission locationPermission = await Geolocator.checkPermission(); if (locationPermission != LocationPermission.denied || locationPermission != LocationPermission.deniedForever) { emit(const LocationLoading()); try { Position position = await Geolocator.getCurrentPosition( desiredAccuracy: LocationAccuracy.best); emit(LocationLoaded( longitude: position.longitude, latitude: position.latitude)); } catch (error) { emit(const LocationError( message: 'Error occured while fetching location')); } } else { Geolocator.requestPermission(); } } }
Location_state.dart
part of 'location_cubit.dart'; abstract class LocationState extends Equatable { const LocationState(); @override List<Object?> get props => []; } class LocationInitial extends LocationState { const LocationInitial(); } class LocationLoading extends LocationState { const LocationLoading(); } class LocationLoaded extends LocationState { const LocationLoaded({ required this.longitude, required this.latitude, }); final double longitude; final double latitude; @override List<Object?> get props => [latitude, longitude]; } class LocationError extends LocationState { final String message; const LocationError({ required this.message, }); }
pubspec.yaml 依赖
dependencies: flutter: sdk: flutter flutter_map: ^3.0.0 latlong2: ^0.8.1 geolocator: ^9.0.2 flutter_bloc: ^8.1.1 equatable: ^2.0.5 bloc: ^8.1.0 cupertino_icons: ^1.0.2
解决方法
1. 移除onReady调用
flutter_map 3.0.0版本的MapController已经移除了onReady属性。直接调用move方法即可,因为当FlutterMap组件初始化完成后,MapController就处于可用状态:
if (currState is LocationLoaded) { _mapController.move( LatLng(currState.latitude, currState.longitude), 15 ); }
2. 修复权限判断逻辑
原LocationCubit中的权限判断条件逻辑错误,会导致无论权限状态如何都会执行定位请求。修改为:
if (locationPermission != LocationPermission.denied && locationPermission != LocationPermission.deniedForever) { // 原有定位逻辑 } else { await Geolocator.requestPermission(); }
或者更明确地判断授权状态:
if (locationPermission == LocationPermission.whileInUse || locationPermission == LocationPermission.always) { // 原有定位逻辑 } else { await Geolocator.requestPermission(); }
3. 可选:使用onMapReady回调确保地图初始化完成
如果需要严格确保地图完全初始化后再执行操作,可以在MapOptions中设置onMapReady回调,在这里触发定位请求:
options: MapOptions( center: LatLng(51.509364, -0.128928), zoom: 15, minZoom: 4, onMapReady: () { context.read<LocationCubit>().getLocation(); }, ),
内容的提问来源于stack exchange,提问作者Diraph
相关产品推荐
相关产品推荐

