【问题标题】:Flutter set Polyline on map failed颤振在地图上设置折线失败
【发布时间】:2020-05-30 20:52:30
【问题描述】:

我创建了一个函数来设置Polyline,但当我尝试使用getCoordinatesWithLocation时总是返回null。

我的代码

void setPolyLines(LatLng destination) async {
  List<LatLng> result;
  try {
    _polylinePoints = GoogleMapPolyline(apiKey: apiKey);
    result = await _polylinePoints.getCoordinatesWithLocation(
      origin: sourceLocation,
      destination: destination,
      mode: RouteMode.driving,
    );
  } on Exception catch (e) {
    print("ERROR GAN: " + e.toString());
  }

  print("=============================================");
  print(sourceLocation);
  print(destination);
  print("=============================================");

  if (result != null) {
    result.forEach((LatLng point) {
      _polylineCoordinates.add(LatLng(point.latitude, point.longitude));
    });
  } else {
    print("GAGAL DAPET POLYLINE");
  }

  Polyline poly = Polyline(
    polylineId: PolylineId("Polylines"),
    color: _polyLineColor,
    points: _polylineCoordinates,
    width: 5,
  );

  _polylines.add(poly);
  notifyListeners();
}

我尝试打印sourceLocationdestination,然后打印就可以了。我的位置和目的地 Latlng 很好。

但为什么总是在我的结果变量中返回 null?

我的完整代码

class MapProvider extends ChangeNotifier {
  //------------------------//
  //   PROPERTY SECTIONS    //
  //------------------------//

  //Property zoom camera
  double _cameraZoom = 16;
  double get cameraZoom => _cameraZoom;

  //Property camera position
  CameraPosition _cameraPosition;
  CameraPosition get cameraPosition => _cameraPosition;

  //Property camera tilt
  double _cameraTilt = 0;
  double get cameraTilt => _cameraTilt;

  //Property camera bearing
  double _cameraBearing = 30;
  double get cameraBearing => _cameraBearing;

  //Property my location data
  LatLng _sourceLocation;
  LatLng get sourceLocation => _sourceLocation;

  //Property tubles list
  List<TublesModel> _tublesList = TublesServices.getTubles();
  List<TublesModel> get tublesList => _tublesList;

  //Property tubles item filter
  //this variable will use when you activate
  //the search features
  List<TublesModel> _filteredTubles;
  List<TublesModel> get filteredTubles => _filteredTubles;

  //Property Google Map Controller completer
  Completer<GoogleMapController> _completer = Completer();
  Completer<GoogleMapController> get completer => _completer;

  //Property Google Map Controller
  GoogleMapController _controller;
  GoogleMapController get controller => _controller;

  //Property to save all markers
  Set<Marker> _markers = {};
  Set<Marker> get markers => _markers;

  //Property to save all polylines
  Set<Polyline> _polylines = {};
  Set<Polyline> get polylines => _polylines;

  //Property to save all direction coordinate routes
  List<LatLng> _polylineCoordinates = [];
  List<LatLng> get polylineCoordinates => _polylineCoordinates;

  // which generates every polyline between start and finish
  GoogleMapPolyline _polylinePoints;
  GoogleMapPolyline get polylinePoints => _polylinePoints;

  //Your google maps API
  //Please enable this API Features:
  //- Google Maps for Android SDK
  //- Place API
  //- Directions API
  String _googleAPIKey = "xxxxxxxxxxxx";
  String get apiKey => _googleAPIKey;

  //Property to handle selected tubles
  TublesModel _tublesSelected;
  TublesModel get tublesSelected => _tublesSelected;

  //Property to handle if the users navigate to tubles or not
  bool _isNavigate = false;
  bool get isNavigate => _isNavigate;

  //Property to mapStyle
  String _mapStyle;
  String get mapStyle => _mapStyle;

  //Property polylines color
  Color _polyLineColor = Colors.amber;

  //Property location services
  Location location = new Location();
  StreamSubscription<LocationData> locationSubscription;

  //Property to save buildcontext
  BuildContext _context;
  BuildContext get context => _context;

  ///Custom key for custom marker
  final markerKey = GlobalKey();
  final myLocationKey = GlobalKey();

  /// Property to save distance in navigate mode
  String _distance = "0 meter";
  String get distance => _distance;

  //------------------------//
  //   FUNCTION SECTIONS   //
  //------------------------//

  //Function to initialize camera
  void initCamera(BuildContext context) async {
    //Get current locations
    await initLocation();

    //Set current location to camera
    _cameraPosition = CameraPosition(
      zoom: cameraZoom,
      bearing: cameraBearing,
      tilt: cameraTilt,
      target: sourceLocation,
    );

    //Set context
    _context = context;
    notifyListeners();
  }

  //Function to get current locations
  void initLocation() async {
    var locData = await location.getLocation();
    _sourceLocation = LatLng(locData.latitude, locData.longitude);
    notifyListeners();
  }

  //Function to listening user location changed
  void listeningLocation() {
    //Adding location listener
    locationSubscription =
        location.onLocationChanged().listen((LocationData data) async {
      var locData = LatLng(data.latitude, data.longitude);

      /// Set current location
      setMyLocation(locData);

      /// Get distance
      getDistance(locData);
    });
  }

  //Function to stop listening location changed
  void stopListeningLocation() {
    locationSubscription.cancel();
  }

  /// Function to set current location
  void setMyLocation(LatLng loc) {
    _sourceLocation = loc;
    print(loc.toString());

    updateMyLocationMaker(true, false);
    notifyListeners();
  }

  /// Function to get distance between two locations
  void getDistance(LatLng myLocation) async {
    _distance = await calculateDistance(myLocation, tublesSelected.location);
    notifyListeners();
  }

  //Function to change camera position
  void changeCameraPosition(LatLng location,
      {bool useBearing = false, bool customZoom = false}) {
    // _controller.animateCamera(CameraUpdate.newLatLngZoom(
    //   LatLng(location.latitude, location.longitude), cameraZoom));
    _controller.animateCamera(
      CameraUpdate.newCameraPosition(
        CameraPosition(
          target: LatLng(location.latitude, location.longitude),
          bearing: useBearing == true ? cameraBearing : 0,
          zoom: customZoom == true ? 18 : cameraZoom,
        ),
      ),
    );

    notifyListeners();
  }

  //Function to handle when maps created
  void onMapCreated(GoogleMapController controller) async {
    //Loading map style
    _mapStyle = await rootBundle.loadString(Config.mapStyleFile);

    _completer.complete(controller);
    _controller = controller;

    //Set style to map
    _controller.setMapStyle(_mapStyle);

    setMapPins(sourceLocation, tublesList);

    notifyListeners();
  }

  //Function to set marker into my locations
  void setMyLocationMarker() async {
    ///Create marker point
    Uint8List markerIcon = await getUint8List(myLocationKey);
    notifyListeners();

    _markers.add(
      Marker(
        markerId: MarkerId("sourcePin"),
        position: sourceLocation,
        icon: BitmapDescriptor.fromBytes(markerIcon),
      ),
    );

    notifyListeners();
  }

  //Function to set marker into my locations
  void updateMyLocationMaker(bool customZoom, bool useBearing) async {
    //Change camera position
    if (_controller != null) {
      changeCameraPosition(
        sourceLocation,
        customZoom: customZoom,
        useBearing: useBearing,
      );
    }

    //Remove current marker
    _markers.removeWhere((m) => m.markerId.value == "sourcePin");

    ///Create marker point
    Uint8List markerIcon = await getUint8List(myLocationKey);
    notifyListeners();
    //Adding new marker
    _markers.add(
      Marker(
        markerId: MarkerId("sourcePin"),
        position: sourceLocation,
        icon: BitmapDescriptor.fromBytes(markerIcon),
      ),
    );

    notifyListeners();
  }

  //Function to pin my location and tubles list
  void setMapPins(
      LatLng sourceLocation, List<TublesModel> destinationList) async {
    //Set my location marker
    setMyLocationMarker();

    for (int i = 0; i < destinationList.length; i++) {
      var data = destinationList[i];

      _tublesSelected = data;
      await Future.delayed(Duration(milliseconds: 100));

      ///Create marker point
      Uint8List markerIcon = await getUint8List(markerKey);
      notifyListeners();

      _markers.add(
        Marker(
          markerId: MarkerId(data.title),
          position: data.location,
          icon: BitmapDescriptor.fromBytes(markerIcon),
          onTap: () => setSelected(data),
        ),
      );
    }

    notifyListeners();
  }

  /// Function to search tubles location by keyword
  void searchTubles(String keyword) async {
    /// Filter search by title
    if (keyword.length > 0) {
      _filteredTubles = tublesList
          .where((element) =>
              element.title.toLowerCase().contains(keyword.toLowerCase()))
          .toList();
    } else {
      _filteredTubles = null;
    }
    notifyListeners();
  }

  /// Function to handle search click event
  void onItemSearchClick(TublesModel tubles) async {
    /// Set filtered to null
    _filteredTubles = null;
    notifyListeners();

    /// Set selected tubles
    changeCameraPosition(sourceLocation, customZoom: true);
    await setSelected(tubles, fromSearch: true);

    navigate();
  }

  //Function to set selected tubles
  void setSelected(TublesModel data, {bool fromSearch = false}) async {
    _tublesSelected = data;

    //Remove previous polylines
    await clearPolylines();

    if (fromSearch == false) {
      //Set polyline ketika klik marker
      await setPolyLines(data.location);
    }

    if (fromSearch == false) {
      /// Change Pageview position
      int index = tublesList.indexOf(data);
      Provider.of<PageProvider>(context, listen: false).navigatePageTo(index);
    }

    notifyListeners();
  }

  //Function to create a polylines into maps
  void setPolyLines(LatLng destination) async {
    List<LatLng> result;
    try {
      _polylinePoints = GoogleMapPolyline(apiKey: apiKey);
      result = await _polylinePoints.getCoordinatesWithLocation(
        origin: sourceLocation,
        destination: destination,
        mode: RouteMode.driving,
      );
    } on Exception catch (e) {
      print("ERROR GAN: " + e.toString());
    }

    print("=============================================");
    print(sourceLocation);
    print(destination);
    print("=============================================");

    if (result != null) {
      result.forEach((LatLng point) {
        _polylineCoordinates.add(LatLng(point.latitude, point.longitude));
      });
    } else {
      print("GAGAL DAPET POLYLINE");
    }

    Polyline poly = Polyline(
      polylineId: PolylineId("Polylines"),
      color: _polyLineColor,
      points: _polylineCoordinates,
      width: 5,
    );

    _polylines.add(poly);
    notifyListeners();
  }

  //Function to clear all polylines
  void clearPolylines() {
    _polylines.clear();
    _polylineCoordinates.clear();
    notifyListeners();
  }

  //Function to navigate into tubles destination
  void navigate({TublesModel tubles}) async {
    if (tubles != null) {
      await setSelected(tubles);
    }

    //Removing previous marker and polylines
    _markers.clear();
    clearPolylines();

    // _tublesSelected = await tubles;
    await Future.delayed(Duration(milliseconds: 100));

    ///Create marker point
    Uint8List markerIcon = await getUint8List(markerKey);
    notifyListeners();

    //Adding new marker destination
    _markers.add(Marker(
      markerId: MarkerId(tublesSelected.title),
      position: tublesSelected.location,
      icon: BitmapDescriptor.fromBytes(markerIcon),
    ));

    //Set my location marker
    setMyLocationMarker();

    //Set polylines to marker
    setPolyLines(tublesSelected.location);

    //set navigate status
    _isNavigate = true;

    /// Get Distance between two locations
    getDistance(sourceLocation);

    //Enable location listener
    listeningLocation();

    notifyListeners();
  }

  //Function to stop navigation
  void stopNavigate() {
    _isNavigate = false;
    _markers.clear();
    clearPolylines();

    setMapPins(sourceLocation, tublesList);

    //Stop listening location
    stopListeningLocation();

    /// Reset page item
    Provider.of<PageProvider>(context, listen: false).resetPageView();

    /// Reinitialize locations
    initLocation();
    updateMyLocationMaker(false, true);

    notifyListeners();
  }

  //Dialog to show if we want to go to destination or not
  void dialogNavigate(BuildContext context, TublesModel tubles) {
    DialogUtils.showDialogChoose(
        context, "Navigasi Tubles", "Anda yakin ingin pergi ke lokasi ini?",
        () {
      //On Yes
      Navigator.pop(context);
      changeCameraPosition(sourceLocation, customZoom: true);
      navigate(tubles: tubles);
    }, () {
      //On No
      Navigator.pop(context);
    });
  }

  /// Dialog to handle if we already in destination and want to checkin
  void dialogCheckin(BuildContext context) {
    DialogUtils.showDialogChoose(
        context, "Checkin Navigasi", "Anda sudah sampai ditempat tujuan?", () {
      //On Yes
      Navigator.pop(context);
      stopNavigate();
    }, () {
      //On No
      Navigator.pop(context);
    });
  }

  /// Converting Widget to PNG
  Future<Uint8List> getUint8List(GlobalKey widgetKey) async {
    RenderRepaintBoundary boundary =
        widgetKey.currentContext.findRenderObject();
    var image = await boundary.toImage(pixelRatio: 2.0);
    ByteData byteData = await image.toByteData(format: ImageByteFormat.png);
    return byteData.buffer.asUint8List();
  }

  /// Calculate distance between two location
  Future<String> calculateDistance(
      LatLng firstLocation, LatLng secondLocation) async {
    var p = 0.017453292519943295;
    var c = cos;
    var a = 0.5 -
        c((secondLocation.latitude - firstLocation.latitude) * p) / 2 +
        c(firstLocation.latitude * p) *
            c(secondLocation.latitude * p) *
            (1 - c((secondLocation.longitude - firstLocation.longitude) * p)) /
            2;
    var distance = 12742 * asin(sqrt(a));

    if (distance < 1) {
      return (double.parse(distance.toStringAsFixed(3)) * 1000)
              .toString()
              .split(".")[0] +
          " meter";
    } else {
      return double.parse(distance.toStringAsFixed(2)).toString() + " km";
    }
  }
}

我的虚拟数据

import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:tubles/core/models/tubles_model.dart';

class TublesServices {
  static List<TublesModel> getTubles() {
    return <TublesModel>[
      TublesModel(
        title: "Tambal Ban Eko",
        description: "Menerima jasa tambah angin dan tambal ban bocor",
        location: LatLng(
          -6.151008613353333,
          106.81737542152405,
        ),
      ),
      TublesModel(
        title: "Tambal Ban Purwanta",
        description: "Ban bocor udah jadi makanan sehari-hari kami",
        location: LatLng(
          -6.149291212377793,
          106.82282567024231,
        ),
      ),
      TublesModel(
        title: "Tambal Ban Dirgahayu",
        description: "Menerima segala jenis ban bocor dan angin",
        location: LatLng(
          -6.153622038975415,
          106.82315826416017,
        ),
      ),
      TublesModel(
        title: "Tambal Ban Adimakmur",
        description: "Isi angin harga murah dan alat lengkap",
        location: LatLng(
          -6.154624737639637,
          106.81607723236085,
        ),
      ),
      TublesModel(
        title: "Tambal Ban Yurani",
        description:
            "Menerima pelayanan spesial ban bocor, ganti karet ban, pelek, dan isi angin",
        location: LatLng(
          -6.1452910333251065,
          106.81787967681886,
        ),
      ),
    ];
  }
}

是否缺少代码片段?

注意:我的 google api 已经 启用 用于 Google Maps for Android SDKPlace APIDirections API

【问题讨论】:

    标签: google-maps flutter dart


    【解决方案1】:

    “getCoordinatesWithLocation”是“Directions API”服务,它不是免费的 因此,您需要在 google 控制台中从您的项目中激活 Directions API 以将其附加到您的 API 密钥,并且不要忘记启用计费

    在那之后 使用您的 API KEY 尝试此 url 以确保服务正常运行

    https://maps.googleapis.com/maps/api/directions/json?origin=Toronto&destination=Montreal&key=YOUR_API_KEY

    【讨论】:

      【解决方案2】:

      启用您的 Api 服务后,请确保您使用 google 在您的云服务上启用计费帐户,Direction API 不是免费的。

      【讨论】:

        猜你喜欢
        • 2019-12-16
        • 2020-07-26
        • 2021-07-28
        • 1970-01-01
        • 1970-01-01
        • 2020-09-27
        • 2021-01-02
        • 2018-03-05
        • 1970-01-01
        相关资源
        最近更新 更多