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

Flutter Google Maps实时动态多边形绘制:基于设备移动位置的实地区域追踪技术问询

Solution: Dynamic Polygon Drawing Based on Real-Time Device Location in Flutter Google Maps

Got it, let's adapt your existing manual polygon drawing code to work with real-time device location. Here's a step-by-step implementation that lets you add vertices as you walk to key points, then close the polygon when you return to the starting point:

1. Update Dependencies (if needed)

First, make sure you have the geolocator package installed to handle high-accuracy real-time location updates. Add it to your pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
  google_maps_flutter: ^2.5.0
  geolocator: ^10.1.0

2. Modified State Class Implementation

Here's the updated state code with real-time location tracking, vertex addition, and polygon closure logic:

import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:geolocator/geolocator.dart';

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

  @override
  State<MyMapScreen> createState() => _MyMapScreenState();
}

class _MyMapScreenState extends State<MyMapScreen> {
  Position? _currentPosition;
  late StreamSubscription<Position> _positionSubscription;
  
  Set<Marker> _markers = {};
  Set<Polygon> _polygons = {};
  List<LatLng> polygonLatLngs1 = [];
  
  // Define your preferred colors
  final Color strokeColor = Colors.blue;
  final Color fillColor = Colors.blue.withOpacity(0.2);

  @override
  void initState() {
    super.initState();
    _startRealTimeLocationTracking();
  }

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

  // Start listening to real-time location updates
  void _startRealTimeLocationTracking() {
    _positionSubscription = Geolocator.getPositionStream(
      locationSettings: const LocationSettings(
        accuracy: LocationAccuracy.high, // High accuracy for walking paths
        distanceFilter: 1, // Update location every 1 meter moved
      ),
    ).listen((Position position) {
      setState(() {
        _currentPosition = position;
      });
    });
  }

  // Update the polygon with the latest vertex list
  void _updatePolygon() {
    setState(() {
      _polygons.clear();
      // Only draw if we have at least 3 vertices
      if (polygonLatLngs1.length >= 3) {
        _polygons.add(Polygon(
          polygonId: const PolygonId("tracking-area"),
          points: polygonLatLngs1,
          strokeWidth: 2,
          strokeColor: strokeColor,
          fillColor: fillColor,
        ));
      } else if (polygonLatLngs1.length == 2) {
        // Optional: Draw a preview line between first two points
        _polygons.add(Polygon(
          polygonId: const PolygonId("tracking-area"),
          points: polygonLatLngs1,
          strokeWidth: 2,
          strokeColor: strokeColor,
          fillColor: Colors.transparent,
        ));
      }
    });
  }

  // Add current location as a polygon vertex (call this when you reach a key point)
  void drawPolygonNow() {
    if (_currentPosition == null) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Waiting for location data...')),
      );
      return;
    }
    setState(() {
      polygonLatLngs1.add(LatLng(
        _currentPosition!.latitude,
        _currentPosition!.longitude,
      ));
      _updatePolygon();
    });
  }

  // Close the polygon when back to starting point
  void closePolygon() {
    if (polygonLatLngs1.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Add at least one vertex first!')),
      );
      return;
    }

    final startPoint = polygonLatLngs1.first;
    final currentPoint = polygonLatLngs1.last;
    // Calculate distance between current position and starting point (in meters)
    final distance = Geolocator.distanceBetween(
      startPoint.latitude,
      startPoint.longitude,
      currentPoint.latitude,
      currentPoint.longitude,
    );

    if (distance < 10) { // Consider 10 meters as "back to start"
      setState(() {
        // Add starting point again to close the polygon
        polygonLatLngs1.add(startPoint);
        _updatePolygon();
      });
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Polygon closed successfully!')),
      );
    } else {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Move ${distance.toStringAsFixed(0)} meters back to the starting point to close.')),
      );
    }
  }

  // Reset polygon data
  void resetPolygon() {
    setState(() {
      polygonLatLngs1.clear();
      _polygons.clear();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          GoogleMap(
            initialCameraPosition: CameraPosition(
              target: LatLng(
                _currentPosition?.latitude ?? 0.0,
                _currentPosition?.longitude ?? 0.0,
              ),
              zoom: 18.0, // Close zoom for walking paths
            ),
            polygons: _polygons,
            myLocationEnabled: true, // Show real-time location marker
            myLocationButtonEnabled: true,
            onCameraMove: (CameraPosition position) {
              // Keep your existing onCameraMove logic here
            },
          ),
          // Control buttons for adding vertices, closing, and resetting
          Positioned(
            bottom: 30,
            left: 20,
            right: 20,
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                ElevatedButton(
                  onPressed: drawPolygonNow,
                  child: const Text('Add Vertex'),
                ),
                ElevatedButton(
                  onPressed: closePolygon,
                  child: const Text('Close Polygon'),
                ),
                ElevatedButton(
                  onPressed: resetPolygon,
                  child: const Text('Reset'),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

3. Key Changes Explained

  • Real-Time Location Tracking: Uses Geolocator.getPositionStream() to get high-accuracy updates as you move, ensuring we always have your current location.
  • drawPolygonNow(): Replaces the manual onTap logic—tap this button when you reach a vertex (like a corner of the building/forest) to add your current location to the polygon.
  • Polygon Closure: The closePolygon() function checks if you're within 10 meters of the starting point before closing the polygon (you can adjust this distance threshold to fit your needs).
  • Visual Feedback: Shows a preview line when you have 2 vertices, and fills the polygon once it's closed for clear visual confirmation.

4. Usage Tips

  1. Make sure to request location permissions in your app (add the necessary permissions to AndroidManifest.xml and Info.plist).
  2. Start your walk at the desired starting point, tap "Add Vertex" to set the first point.
  3. Walk to each corner/vertex and tap "Add Vertex" to record the position.
  4. When you return to the starting point, tap "Close Polygon" to complete the shape.

内容的提问来源于stack exchange,提问作者Jacob Okello Okomo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 19:17:47