如何在Yandex MapKit Flutter中实现随相机移动的屏幕中心标记
实现Yandex地图中心标记随相机位置同步移动
要让标记始终处于屏幕中心并跟随相机位置移动,核心是将标记作为地图内置的Placemark对象,而非Stack里的静态组件,通过绑定相机的target位置实现同步。具体实现如下:
核心实现步骤
- 维护变量存储当前相机的目标坐标与对应标记对象
- 地图初始化时,创建绑定初始相机位置的标记
- 监听相机位置变化事件,实时更新标记坐标
- 确保缩放、手动拖动地图时,标记始终跟随相机中心
修改后的完整代码
import 'package:flutter/material.dart'; import 'package:yandex_mapkit/yandex_mapkit.dart'; class YandexMapWithFloatingMarker extends StatefulWidget { const YandexMapWithFloatingMarker({super.key}); @override State<YandexMapWithFloatingMarker> createState() => _YandexMapWithFloatingMarkerState(); } class _YandexMapWithFloatingMarkerState extends State<YandexMapWithFloatingMarker> { final Completer<YandexMapController> _completer = Completer(); final List<MapObject> _mapObjects = []; Placemark? _centerMarker; Point? _currentCameraTarget; @override Widget build(BuildContext context) { return Stack( children: [ YandexMap( mapObjects: _mapObjects, onMapCreated: _onMapCreated, onCameraPositionChanged: (CameraPosition position, _, __) { // 监听相机位置变化,实时更新标记坐标 if (_currentCameraTarget?.latitude != position.target.latitude || _currentCameraTarget?.longitude != position.target.longitude) { _updateCenterMarker(position.target); } }, ), // 保留原有缩放按钮布局 Center( child: Padding( padding: const EdgeInsets.only(right: 11), child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ Container( height: 97, width: 40, decoration: const BoxDecoration( color: CupertinoColors.white, borderRadius: BorderRadius.all(Radius.circular(11)), ), child: Column( children: [ IconButton( onPressed: _zoomIn, icon: const Icon(Icons.add), ), IconButton( onPressed: _zoomOut, icon: const Icon(Icons.remove), ), ], ), ) ], ), ), ) ], ); } Future<void> _onMapCreated(YandexMapController controller) async { _completer.complete(controller); const initialTarget = Point(latitude: 55.755864, longitude: 37.617698); // 创建初始中心标记(替换成你自己的图标资源) _centerMarker = Placemark( point: initialTarget, icon: PlacemarkIcon.single( PlacemarkIconStyle( image: BitmapDescriptor.fromAssetImage('assets/marker_icon.png'), scale: 1.0, ), ), ); setState(() { _currentCameraTarget = initialTarget; _mapObjects.add(_centerMarker!); }); await controller.moveCamera( CameraUpdate.newCameraPosition( const CameraPosition( target: initialTarget, zoom: 12, ), ), animation: const MapAnimation(type: MapAnimationType.linear, duration: 1), ); } void _updateCenterMarker(Point newTarget) { if (_centerMarker == null) return; setState(() { _currentCameraTarget = newTarget; // 更新标记位置并刷新地图对象列表 _centerMarker = _centerMarker!.copyWith(point: newTarget); _mapObjects.removeWhere((obj) => obj is Placemark && obj.id == _centerMarker!.id); _mapObjects.add(_centerMarker!); }); } Future<void> _zoomIn() async { final controller = await _completer.future; await controller.moveCamera( CameraUpdate.zoomIn(), animation: const MapAnimation(duration: 1, type: MapAnimationType.smooth), ); } Future<void> _zoomOut() async { final controller = await _completer.future; await controller.moveCamera( CameraUpdate.zoomOut(), animation: const MapAnimation(duration: 1, type: MapAnimationType.smooth), ); } }
关键说明
- 利用
onCameraPositionChanged监听相机位置变化,确保标记与相机中心实时同步 - 通过
Placemark.copyWith更新标记位置,保证地图能实时刷新显示 - 标记采用地图内置的Placemark组件,而非Stack静态元素,可完美适配相机的所有移动场景(拖动、缩放、动画跳转等)
内容的提问来源于stack exchange,提问作者Alexandr Sergo
相关产品推荐
相关产品推荐

