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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 08:35:00