如何在一张 Google 地图上显示 Flutter 中的多组折线

How to show multiple sets of polylines in Flutter on one Google map

我正在尝试显示多组不同的折线(每组代表一条具有自己起点和终点的自行车路线)。

我从 JSON 文件中引入了总共十条路线。问题是 map 正在将所有单独的十条路线合并为一条巨大的折线。

所以它有点把它们连接在一起(你可以找出每条路线之间的直线连接,只有一个 startCapendCap 图标)。

我会 expect/want 看到十个不同的 startCapendCap 图标以及 每个折线集之间 的空格。

那么如何让 map 将每条折线路线显示为不同的路线?

我正在使用 flutter_polyline_points 解码通往 google map 的折线路线。

下面的代码和 JSON 已上线 link 如果有帮助,可以轻松模拟。

本质上步骤

  1. 我创建了 google 地图,上面有一个主要的中央标记。

  2. 然后我从 JSON 文件中引入十个路由。这些是名为 Segments 的数组中的十个对象。每个对象都有我用于 PolyLineid 的唯一 ID 和字符串中一组唯一的折线点。所以我引入了 JSON 然后.

  3. 遍历每个对象并将多段线字符串解码为多段线坐标,然后我尝试将其作为多条多段线添加到地图中。

这里还有我看到的输出,使问题栩栩如生。


import 'package:flutter_polyline_points/flutter_polyline_points.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Multiple Polylines',
      theme: ThemeData(
        primarySwatch: Colors.orange,
      ),
      home: MapScreen(),
    );
  }
}

class MapScreen extends StatefulWidget {
  @override
  _MapScreenState createState() => _MapScreenState();
}

class _MapScreenState extends State<MapScreen> {
  GoogleMapController mapController;
  final Set<Marker> _marker = {};
  List<LatLng> polylineCoordinates = [];
  final Set<Polyline> _polylines = {};
  PolylinePoints polylinePoints = PolylinePoints();
  String lat = '51.200000';
  String long = '-0.440000';
  String title = 'Surrey Hills Mountain Biking';
  String location = 'Walking Bottom Car Park, Peaslake, Surrey';

  Future fetchStrava() async {
    final response = await http.get(
      'https://ibikeride.com/strava.json',
    );
    return parseStrava(response.body);
  }

  Future parseStrava(String responseBody) async {
    final Map<String, dynamic> parsed = await jsonDecode(responseBody);
    parsed['segments'].forEach((parse) {
      drawStrava(parse['points'], parse['id'].toString());
    });
  }

  Future drawStrava(points, polyid) async {
    var result = await polylinePoints.decodePolyline(points);

    if (result.isNotEmpty) {
      result.forEach((PointLatLng point) {
        polylineCoordinates.add(LatLng(point.latitude, point.longitude));
      });
    }

    _getPolyLine(polyid, polylineCoordinates);
  }

  void _getPolyLine(polyid, polyCord) {
    var id = PolylineId(polyid);
    _polylines.add(Polyline(
      polylineId: id,
      color: Colors.blue,
      width: 2,
      jointType: JointType.round,
      startCap: Cap.customCapFromBitmap(BitmapDescriptor.defaultMarker),
      endCap:
          Cap.customCapFromBitmap(BitmapDescriptor.defaultMarkerWithHue(90)),
      points: polyCord,
    ));
    setState(() {});
  }

  @override
  void initState() {
    super.initState();
    polylineCoordinates.clear();
    _marker.add(
      Marker(
          markerId: MarkerId('t'),
          infoWindow: InfoWindow(
            title: (title),
            snippet: (location),
          ),
          position: LatLng(double.parse(lat), double.parse(long)),
          icon: BitmapDescriptor.defaultMarker),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: GoogleMap(
          polylines: _polylines,
          mapType: MapType.hybrid,
          myLocationEnabled: true,
          initialCameraPosition: CameraPosition(
            target: LatLng(double.parse(lat), double.parse(long)),
            zoom: 13,
          ),
          markers: _marker,
          onMapCreated: (GoogleMapController controller) async {
            mapController = controller;
            await fetchStrava();
          },
        ),
      ),
    );
  }
}

JSON 文件内容(在代码中的 link 上) https://ibikeride.com/strava.json 供参考:

{
    "segments": [
        {
            "id": 3592388,
            "name": "Barry Knows Best",
            "points": "uokwHvdtA@hAR`B^bBRnAQp@c@^w@b@o@t@Uv@c@r@c@hAsAxDOd@y@lDk@t@WVw@VeCl@u@\@^k@jAKNi@b@iCVFBj@Cx@WpBKpA_@d@@Fn@W^c@RYBIHJ^"
        },
        {
            "id": 10925800,
            "name": "Combe Ln ",
            "points": "eauwHhezAHR@ZSlE?zDB|ALxAz@tGf@lCb@pA^|@j@l@XPvBf@bCL~BAdCMxA@Z?XDr@RTBT@h@?b@KLIPo@TuAJYPYz@u@~@aAn@]bAc@tCaA"
        },
        {
            "id": 22105173,
            "name": "Charlie & Mai's Rollercoast",
            "points": "wblwHfqvA_@@e@Es@Le@CI@]?YEE@CD@HT\@H?HEHm@PWAKBW@G?KGIAOFWMQEQD_@@OCc@?MBEFYHI?KFGEE?ARVNFCj@B^?`@LR?HCJHX@NCXDg@TEEi@PS?WHGBEJOJE@GAOT[HG?K@KFCBKTBDSXg@F[ZECWZCP"
        },
        {
            "id": 2575161,
            "name": "Yoghurt Pots.",
            "points": "wljwHdoqASQKa@QIGSHOj@SHg@I[Ha@G[W[WiAa@Yc@UU_@k@UWE[Fg@Wc@OQQ_AC_AGa@He@Iy@Ii@AUSOAk@BSd@a@TS@MR"
        },
        {
            "id": 21544370,
            "name": "Shere to Gomshall",
            "points": "caswH`lxA?iCImCU{DM_DS_ICeKPiCJuCPwCZiAVe@X_@fBmBz@eA"
        },
        {
            "id": 14062811,
            "name": "Shere to Little London",
            "points": "ysrwHjxyAVVr@~AHL`@Xb@Hd@CVGd@G~Bg@z@YjAOl@Kl@Gt@O~@?f@G|@E~@MZIf@GtAWdA?b@N"
        },
        {
            "id": 20763954,
            "name": "All the Novas",
            "points": "uckwHvvwAc@Gk@MmB{@q@KSK[Yc@s@OS[SQEQCSUQIGIIOSiA[aAGKa@_@OKmA{A_Ai@w@q@[Qi@MgA?i@IUOg@Qe@IUOWUWMK?UFSBG?[Oq@Di@MYB]CK@MD[\GDI?q@MKB"
        },
        {
            "id": 11514010,
            "name": "Captain Clunk (before the drops)",
            "points": "yqiwH|kwAMWGAg@NaA@}@VM@MCk@UOCs@@i@[ME_@EYFe@XQF_AJ"
        },
        {
            "id": 23855128,
            "name": "Abinger - Hammer to Sutton",
            "points": "{{qwH|hsA~@K`Bw@hA_@nAO`CCbAJ\H~CbAjCxAh@RZFn@@rAKnAUhBk@j@KZ@ZJdAp@ND\@NC\KfAs@r@u@v@uARg@|@iDn@yAt@iA|AiBp@cAXq@lAcERa@VYZQt@Y|@UTQ`@w@t@qBPu@L{@\wIH}@pBeM"
        },
        {
            "id": 13501471,
            "name": "Whitedown, turnoff till switchback",
            "points": "garwHbxoAsAaA_A]uA[yC_@UG_@Ys@u@kAy@eA{@mAq@k@e@eCkCiBuBu@w@e@m@_A_AaAqAgAqAu@Us@BcBViADeACqC]}A?k@F"
        }
    ]
}

I'm pretty new to coding but enjoying the journey.

我在 Medium 上搜索了很多次这个问题,并且看了没完没了的 youtube 视频,但仍然一头雾水。任何指点表示赞赏。

我感觉这与创建一个 list 独特的 Polyines 迭代添加有关。非常感谢

您必须创建包含经纬度的对象列表。将折线坐标和标记添加到列表中。如 link.

中所示
  1. 创建一个生成折线的方法:

     Future<Polyline> _getRoutePolyline(
       {required LatLng start,
       required LatLng finish,
       required Color color,
       required String id,
       int width = 6}) async {
     // Generates every polyline between start and finish
     final polylinePoints = PolylinePoints();
     // Holds each polyline coordinate as Lat and Lng pairs
     final List<LatLng> polylineCoordinates = [];
    
     final startPoint = PointLatLng(start.latitude, start.longitude);
     final finishPoint = PointLatLng(finish.latitude, finish.longitude);
    
     final result = await polylinePoints.getRouteBetweenCoordinates(
       _googleApiKey,
       startPoint,
       finishPoint,
     );
     if (result.points.isNotEmpty) {
       // loop through all PointLatLng points and convert them
       // to a list of LatLng, required by the Polyline
       result.points.forEach((PointLatLng point) {
         polylineCoordinates.add(
           LatLng(point.latitude, point.longitude),
         );
       });
     }
     final polyline = Polyline(
       polylineId: PolylineId(id),
       color: color,
       points: polylineCoordinates,
       width: width,
     );
     return polyline;
     }
    
  2. 生成任意数量的折线:

     Future<Set<Polyline>> _getTwoPolylines() async {
     // Use your location.
     const firstPolylineStart = LatLng(49.818453, 24.076606);
     const firstPolylineFinish = LatLng(49.834409, 24.067875);
    
     final firsPolyline = await _getRoutePolyline(
       start: firstPolylineStart,
       finish: firstPolylineFinish,
       color: Colors.green,
       id: 'firstPolyline',
     );
    
     // Use your location.
     const secondPolylineStart = LatLng(49.836510, 24.064096);
     const secondPolylineFinish = LatLng(49.840191, 24.043384);
    
     final secondPolyline = await _getRoutePolyline(
       start: secondPolylineStart,
       finish: secondPolylineFinish,
       color: Colors.red,
       id: 'secondPolyline',
     );
    
     final Set<Polyline> polylines = {};
     polylines.add(firsPolyline);
     polylines.add(secondPolyline);
    
     return polylines;
     }
    
  3. 将生成的折线设置为GoogleMappolylines字段)。