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

地图位置移动时更新餐厅标记的Flutter技术求助

问题:地图移动后无法加载新区域的餐厅标记

我通过Google Places API实现了基于当前位置显示附近餐厅的Flutter功能,但手动移动手机地图位置后,新区域的餐厅标记无法加载显示。尝试过用Google Maps的onCameraMove方法更新标记但未成功,恳请协助解决基于新相机位置更新餐厅标记的问题。

import 'package:family_farms_forever/utilities/secrets.dart';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:google_maps_webservice/places.dart';
import 'package:google_maps_flutter_platform_interface/src/types/marker_updates.dart';

void main() => runApp(const MyApp());

final places = GoogleMapsPlaces(apiKey: Secrets.iosApiKey);

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Market Map",
      home: Scaffold(
          appBar: AppBar(title: const Text("My Location")),
          body: const MyMarketMap()),
    );
  }
}

class MyMarketMap extends StatefulWidget {
  const MyMarketMap({super.key});

  @override
  State<StatefulWidget> createState() {
    return _MyMarketMapState();
  }
}

class _MyMarketMapState extends State<MyMarketMap> {
  late Future<Position> _currentLocation;
  late final Set<Marker> _markers = {};
  GoogleMapController? _mapController;
  Timer? _debounceTimer;
  LatLng? _lastRequestedLocation;

  @override
  void initState() {
    super.initState();
    _currentLocation = Geolocator.getCurrentPosition();
  }

  Future<void> _retrieveNearbyRestaurants(LatLng targetLocation) async {
    if (_lastRequestedLocation != null &&
        Geolocator.distanceBetween(
          _lastRequestedLocation!.latitude,
          _lastRequestedLocation!.longitude,
          targetLocation.latitude,
          targetLocation.longitude,
        ) < 500) {
      return;
    }
    _lastRequestedLocation = targetLocation;

    PlacesSearchResponse response = await places.searchNearbyWithRadius(
        Location(lat: targetLocation.latitude, lng: targetLocation.longitude),
        10000,
        type: "restaurant");

    _markers.removeWhere((marker) => marker.markerId.value != "User Location");

    Set<Marker> restaurantMarkers = response.results
        .map((result) => Marker(
            markerId: MarkerId(result.name),
            icon: BitmapDescriptor.defaultMarkerWithHue(
                BitmapDescriptor.hueAzure),
            infoWindow: InfoWindow(
                title: result.name,
                snippet:
                    "Ratings: ${result.rating?.toString() ?? "Not Rated"}"),
            position: LatLng(
                result.geometry!.location.lat, result.geometry!.location.lng)))
        .toSet();

    setState(() {
      _markers.addAll(restaurantMarkers);
    });
  }

  void _handleCameraMove(CameraPosition position) {
    if (_debounceTimer != null) {
      _debounceTimer!.cancel();
    }
    _debounceTimer = Timer(const Duration(milliseconds: 500), () {
      _retrieveNearbyRestaurants(position.target);
    });
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
        future: _currentLocation,
        builder: (context, AsyncSnapshot snapshot) {
          if (snapshot.connectionState == ConnectionState.done) {
            if (snapshot.hasData) {
              Position snapshotData = snapshot.data;
              LatLng userLocation =
                  LatLng(snapshotData.latitude, snapshotData.longitude);

              if (_markers.isEmpty) {
                _retrieveNearbyRestaurants(userLocation);
                _markers.add(Marker(
                    markerId: const MarkerId("User Location"),
                    infoWindow: const InfoWindow(title: "User Location"),
                    position: userLocation));
              }

              return GoogleMap(
                onMapCreated: (controller) => _mapController = controller,
                myLocationEnabled: true,
                zoomGesturesEnabled: true,
                onCameraIdle: () => _handleCameraMove(_mapController!.cameraPosition),
                initialCameraPosition: CameraPosition(
                  target: userLocation,
                  zoom: 12,
                ),
                markers: _markers,
              );
            } else {
              return const Center(child: Text("Failed to get user location."));
            }
          }
          return const Center(child: CircularProgressIndicator());
        });
  }

  @override
  void dispose() {
    _debounceTimer?.cancel();
    super.dispose();
  }
}

关键修复点说明

  • 防抖处理:用Timer实现防抖,避免拖动地图时频繁触发API请求,防止超出调用限制
  • 标记清理:每次获取新区域餐厅前,移除旧的餐厅标记(保留用户位置标记),避免标记堆积
  • 位置去重:判断当前请求位置与上次请求位置的距离,小于500米则跳过请求,优化性能
  • 事件选择:改用onCameraIdle事件,在地图停止移动后再触发请求,比onCameraMove更合理

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 23:01:13