Flutter中Google Maps实现用户移动时实时更新位置及路线
解决方案
要实现用户移动时实时更新位置Marker和路线Polyline,你需要对现有代码做以下几处关键修改,核心是监听位置实时变化并同步更新地图元素:
核心修改要点
- 启用位置服务的实时监听,替换一次性获取位置的逻辑
- 优化Marker更新:每次更新用户位置时,移除旧的用户Marker再添加新的,避免重复创建
- 优化Polyline更新:每次获取新路线前清空旧坐标,确保路线是最新的
- 提前处理位置权限,保证能正常获取位置数据
- 静态目的地Marker只初始化一次,避免重复添加
修改后的完整代码
import 'package:flutter/material.dart'; import 'package:flutter_polyline_points/flutter_polyline_points.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:location/location.dart'; import 'package:custom_marker/marker_icon.dart'; import 'package:flutter/services.dart' show rootBundle; import 'CustomMarker.dart'; class MapScreen extends StatefulWidget { @override _MapScreenState createState() => _MapScreenState(); } class _MapScreenState extends State<MapScreen> { GoogleMapController? _controller; final GlobalKey myglobalKey = GlobalKey(); final GlobalKey otherglobalKey = GlobalKey(); Set<Marker> _markers = {}; List<LatLng> polylineCoordinates = []; late String _mapStyle; late Location _location; LocationData? _currentLocation; // 静态目的地坐标 final LatLng _destination = LatLng(28.4212, 70.2989); @override void initState() { super.initState(); _initLocationService(); _loadMapStyle(); // 初始化静态目的地Marker(只执行一次) _initDestinationMarker(); } // 初始化位置服务并启动监听 Future<void> _initLocationService() async { _location = Location(); // 检查位置权限 bool serviceEnabled; PermissionStatus permissionGranted; serviceEnabled = await _location.serviceEnabled(); if (!serviceEnabled) { serviceEnabled = await _location.requestService(); if (!serviceEnabled) return; } permissionGranted = await _location.hasPermission(); if (permissionGranted == PermissionStatus.denied) { permissionGranted = await _location.requestPermission(); if (permissionGranted != PermissionStatus.granted) return; } // 获取初始位置 _currentLocation = await _location.getLocation(); if (_currentLocation != null) { await _updateUserMarker(); await _updatePolyline(); _moveCameraToUser(); } // 监听位置变化 _location.onLocationChanged.listen((LocationData newLocation) { setState(() { _currentLocation = newLocation; }); _updateUserMarker(); _updatePolyline(); // 可选:是否跟随用户位置自动移动相机,取消注释即可开启 // _moveCameraToUser(); }); } // 加载地图样式 void _loadMapStyle() { rootBundle.loadString('assets/mapStyle.txt').then((string) { setState(() { _mapStyle = string; _controller?.setMapStyle(_mapStyle); }); }); } // 初始化目的地Marker Future<void> _initDestinationMarker() async { final destinationIcon = await MarkerIcon.widgetToIcon(otherglobalKey); setState(() { _markers.add( Marker( icon: destinationIcon, markerId: const MarkerId('Destination'), position: _destination, ), ); }); } // 更新用户位置Marker Future<void> _updateUserMarker() async { if (_currentLocation == null) return; final userIcon = await MarkerIcon.widgetToIcon(myglobalKey); // 先移除旧的用户Marker,避免重复显示 _markers.removeWhere((marker) => marker.markerId.value == 'MyLocation'); setState(() { _markers.add( Marker( icon: userIcon, markerId: const MarkerId('MyLocation'), position: LatLng( _currentLocation!.latitude ?? 0.0, _currentLocation!.longitude ?? 0.0, ), ), ); }); } // 更新路线Polyline Future<void> _updatePolyline() async { if (_currentLocation == null) return; PolylinePoints polylinePoints = PolylinePoints(); PolylineResult result = await polylinePoints.getRouteBetweenCoordinates( "AIzaSyBI22C6hc7_C4yRuyEnUPHPJGu3k0GH6PU", PointLatLng( _currentLocation!.latitude ?? 0.0, _currentLocation!.longitude ?? 0.0, ), PointLatLng(_destination.latitude, _destination.longitude), ); if (result.points.isNotEmpty) { setState(() { // 清空旧路线坐标,添加新的路线点 polylineCoordinates.clear(); result.points.forEach((PointLatLng point) => polylineCoordinates.add(LatLng(point.latitude, point.longitude))); }); } } // 移动相机到用户位置 void _moveCameraToUser() { if (_currentLocation == null) return; _controller?.animateCamera( CameraUpdate.newCameraPosition( CameraPosition( target: LatLng( _currentLocation!.latitude ?? 0.0, _currentLocation!.longitude ?? 0.0, ), zoom: 12.0, ), ), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("Map"), backgroundColor: Theme.of(context).scaffoldBackgroundColor, ), body: Stack( children: [ MyMarker(myglobalKey), OtherUserMarker(otherglobalKey), SizedBox( height: MediaQuery.of(context).size.height, width: MediaQuery.of(context).size.width, child: GoogleMap( zoomControlsEnabled: false, initialCameraPosition: const CameraPosition( target: LatLng(0, 0), zoom: 12.0, ), onMapCreated: (GoogleMapController controller) { _controller = controller; if (_mapStyle.isNotEmpty) { _controller?.setMapStyle(_mapStyle); } }, markers: _markers, polylines: { Polyline( polylineId: const PolylineId("route"), points: polylineCoordinates, color: const Color(0xFF7B61FF), width: 6, ), }, ), ), ], ), floatingActionButtonLocation: FloatingActionButtonLocation.endFloat, floatingActionButton: FloatingActionButton( onPressed: _moveCameraToUser, backgroundColor: Theme.of(context).scaffoldBackgroundColor, child: const Icon(Icons.location_searching_rounded, color: Colors.white, size: 20), ), ); } }
关键修改解释
- 位置实时监听:通过
_location.onLocationChanged.listen()持续监听用户位置变化,一旦位置更新就触发Marker和路线的更新 - Marker去重逻辑:每次更新用户位置时,先移除旧的用户Marker,再添加新的,避免地图上出现多个用户位置标记
- 路线更新优化:每次获取新路线前清空旧坐标列表,确保显示的是从当前位置到目的地的最新路线
- 权限前置处理:初始化位置服务时先检查并请求位置权限和服务,避免因权限问题导致无法获取位置数据
- 静态Marker复用:目的地Marker只在初始化时创建一次,不需要重复添加
- 相机控制可选:保留了浮动按钮用于手动定位用户位置,同时提供了自动跟随的注释代码,可按需开启
内容的提问来源于stack exchange,提问作者Umer Yaseen
相关产品推荐
相关产品推荐

