Search This Blog

Sunday, August 26, 2018

Flutter - How can draw route on google map between markers.

Route on google map is the easiest way to reach somewhere. Just enter the address of your source and destination point. After that, you will see the right way to go there and you can control the route map.  Google maps highlight the suggested route in a bright blue color and include other possible routes in gray. It is always safe to use a driving map when you are not aware of the place.



In this post, we'll create a Flutter application for draw route on google map from your current position to the destination address. To get the current location, we will use the GPS handler plugin and for a search destination address, we'll use places API. The final output of the project will be like below.


In our previous post, we have seen the basic setup and implementation of google map plugin in the Flutter Application. If you have never used google map in Flutter. So, you should read our previous post. In this post, we'll not discuss the basic part of google map. We assuming here, you have a google map key with enabled google map API for Android and Ios.

So, let start it and see, how we can draw the route on google map in a Flutter Application. 



Creating a new Project
1. Create a new project from File ⇒ New Flutter Project with your development IDE.

2. Include required following dependency in the pubspec.yaml.
location: ^1.4.1
map_view: "^0.0.14"
google_maps_webservice: ^0.0.6
  • location: ^1.4.1 will manage GPS of the device and get current user position.
  • map_view: "^0.0.14" will display google map. We have discussed it in our previous post
  • We using google_maps_webservice: ^0.0.6 for get google places. By using this, we'll able to get destination Address position.   
3. Open main.dart file and edit it. As we have set our theme and change debug banner property of Application.
main.dart
import 'package:flutter/material.dart'; import 'package:flutter_google_map_route/map_screen.dart'; import 'package:map_view/map_view.dart'; void main() { MapView.setApiKey("Google_API_Key"); runApp(new MaterialApp( debugShowCheckedModeBanner: false, theme: new ThemeData( primaryColor: const Color(0xFF02BB9F), primaryColorDark: const Color(0xFF167F67), accentColor: const Color(0xFF167F67), ), home: new MapScreen(), )); }

4. After that create home screen map_screen.dart of the application and start designing it. As you can see above, we have created a destination address widget for search destination location that we'll use for draw route on google map.
map_screen.dart
new GestureDetector( onTap: () { googlePlaces.findPlace(context); }, child: new Container( alignment: FractionalOffset.center, margin: EdgeInsets.all(10.0), padding: EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 10.0), decoration: new BoxDecoration( color: const Color.fromRGBO(255, 255, 255, 1.0), border: Border.all(color: const Color(0x33A6A6A6)), borderRadius: new BorderRadius.all(const Radius.circular(6.0)), ), child: new Row( children: <Widget>[ new Icon(Icons.search), new Flexible( child: new Container( padding: new EdgeInsets.only(right: 13.0), child: new Text( locationAddress, overflow: TextOverflow.ellipsis, style: new TextStyle(color: Colors.black), ), ), ), ], ), ), ),
now create another widget that will display static google map image.
map_screen.dart
new Container( height: 230.0, child: new Stack( children: <Widget>[ new Center( child: Container( child: new Text( "Google Map Box", textAlign: TextAlign.center, ), padding: const EdgeInsets.all(20.0), ), ), new GestureDetector( onTap: () => mapUtil.showMap(), child: new Center( child: new Image.network(mapUtil.getStaticMap().toString()), ), ), ], ), ),
as you can see the final map_screen.dart file below. We have used a Text and Button to get route steps from Google API.
map_screen.dart
import 'package:flutter/material.dart'; import 'package:flutter_google_map_route/progress_hud.dart'; import 'package:flutter_google_map_route/utils/google_place_util.dart'; import 'package:flutter_google_map_route/utils/map_util.dart'; import 'package:map_view/map_view.dart'; class MapScreen extends StatefulWidget { @override _MapScreenState createState() => new _MapScreenState(); } class _MapScreenState extends State<MapScreen> implements ScreenListener, GooglePlacesListener { MapUtil mapUtil; String locationAddress = "Search destination"; String myLocation = ""; GooglePlaces googlePlaces; bool _isLoading = false; double _destinationLat; double _destinationLng; @override void initState() { super.initState(); mapUtil = new MapUtil(this); mapUtil.init(); googlePlaces = new GooglePlaces(this); } @override Widget build(BuildContext context) { var screenWidget = new Column( children: <Widget>[ new GestureDetector( onTap: () { googlePlaces.findPlace(context); }, child: new Container( alignment: FractionalOffset.center, margin: EdgeInsets.all(10.0), padding: EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 10.0), decoration: new BoxDecoration( color: const Color.fromRGBO(255, 255, 255, 1.0), border: Border.all(color: const Color(0x33A6A6A6)), borderRadius: new BorderRadius.all(const Radius.circular(6.0)), ), child: new Row( children: <Widget>[ new Icon(Icons.search), new Flexible( child: new Container( padding: new EdgeInsets.only(right: 13.0), child: new Text( locationAddress, overflow: TextOverflow.ellipsis, style: new TextStyle(color: Colors.black), ), ), ), ], ), ), ), new Container( height: 230.0, child: new Stack( children: <Widget>[ new Center( child: Container( child: new Text( "Google Map Box", textAlign: TextAlign.center, ), padding: const EdgeInsets.all(20.0), ), ), new GestureDetector( onTap: () => mapUtil.showMap(), child: new Center( child: new Image.network(mapUtil.getStaticMap().toString()), ), ), ], ), ), new Container( margin: new EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0), padding: new EdgeInsets.only(top: 10.0), child: new Text( myLocation, style: new TextStyle(fontWeight: FontWeight.bold), ), ), new GestureDetector( onTap: () => getMapRoute(), child: new Container( margin: EdgeInsets.fromLTRB(30.0, 30.0, 30.0, 0.0), padding: EdgeInsets.all(15.0), alignment: FractionalOffset.center, decoration: new BoxDecoration( color: const Color(0xFFFFD900), borderRadius: new BorderRadius.all(const Radius.circular(6.0)), ), child: Text( "Draw Route", style: new TextStyle( color: const Color(0xFF28324E), fontSize: 20.0, fontWeight: FontWeight.bold), ), ), ), ], ); return new Scaffold( backgroundColor: const Color(0xFFA6AFAA), appBar: AppBar( title: new Text( "Google maps route", textAlign: TextAlign.center, style: new TextStyle( fontWeight: FontWeight.bold, color: Colors.white, ), ), ), body: ProgressHUD( child: new SingleChildScrollView( child: screenWidget, ), inAsyncCall: _isLoading, opacity: 0.0, ), ); } Widget getTextField( String inputBoxName, TextEditingController inputBoxController) { var loginBtn = new Padding( padding: const EdgeInsets.all(5.0), child: new TextFormField( controller: inputBoxController, decoration: new InputDecoration( hintText: inputBoxName, ), ), ); return loginBtn; } Widget getButton(String buttonLabel, EdgeInsets margin) { var staticMapBtn = new Container( margin: margin, padding: EdgeInsets.all(8.0), alignment: FractionalOffset.center, decoration: new BoxDecoration( color: const Color(0xFF167F67), border: Border.all(color: const Color(0xFF28324E)), borderRadius: new BorderRadius.all(const Radius.circular(6.0)), ), child: new Text( buttonLabel, style: new TextStyle( color: const Color(0xFFFFFFFF), fontSize: 20.0, fontWeight: FontWeight.w300, letterSpacing: 0.3, ), ), ); return staticMapBtn; } updateStaticMap() { setState(() {}); } @override updateScreen(Location location) { myLocation = "You are at: " + location.latitude.toString() + ", " + location.longitude.toString(); googlePlaces.updateLocation(location.latitude, location.longitude); setState(() {}); } @override selectedLocation(double lat, double lng, String address) { setState(() { _destinationLat = lat; _destinationLng = lng; locationAddress = address; }); } getMapRoute() { setState(() { _isLoading = true; }); mapUtil.getDirectionSteps(_destinationLat, _destinationLng); } @override dismissLoader() { setState(() { _isLoading = false; }); } } abstract class ScreenListener { updateScreen(Location location); dismissLoader(); }
in the above class, we have created instances of the util class to manage map and GPS in the init method. We have a ScreenListener abstract class that will update map_screen.dart widget.




5. Now create flutter_google_places_autocomplete.dart file. It will manage destination widget dialog on the map_screen.dart.
flutter_google_places_autocomplete.dart
library flutter_google_places_autocomplete.src; import 'dart:async'; import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:google_maps_webservice/places.dart'; class GooglePlacesAutocompleteWidget extends StatefulWidget { final String apiKey; final String hint; final Location location; final num offset; final num radius; final String language; final List<String> types; final List<Component> components; final bool strictbounds; final ValueChanged<PlacesAutocompleteResponse> onError; GooglePlacesAutocompleteWidget( {@required this.apiKey, this.hint = "Search", this.offset, this.location, this.radius, this.language, this.types, this.components, this.strictbounds, this.onError, Key key}) : super(key: key); @override State<GooglePlacesAutocompleteWidget> createState() { return new _GooglePlacesAutocompleteOverlayState(); } static GooglePlacesAutocompleteState of(BuildContext context) => context .ancestorStateOfType(const TypeMatcher<GooglePlacesAutocompleteState>()); } class _GooglePlacesAutocompleteOverlayState extends GooglePlacesAutocompleteState { @override Widget build(BuildContext context) { final header = new Column(children: <Widget>[ new Material( child: new Row( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ new IconButton( color: Colors.black45, icon: new Icon(Icons.arrow_back), onPressed: () { Navigator.pop(context); }, ), new Expanded( child: new Padding( child: _textField(), padding: const EdgeInsets.only(right: 8.0), )), ], )), new Divider( //height: 1.0, ) ]); var body; if (query.text.isEmpty || response == null || response.predictions.isEmpty) { body = new Material( color: Colors.white, borderRadius: new BorderRadius.only( bottomLeft: new Radius.circular(2.0), bottomRight: new Radius.circular(2.0)), ); } else { body = new SingleChildScrollView( child: new Material( borderRadius: new BorderRadius.only( bottomLeft: new Radius.circular(2.0), bottomRight: new Radius.circular(2.0)), color: Colors.white, child: new ListBody( children: response.predictions .map((p) => new PredictionTile( prediction: p, onTap: Navigator.of(context).pop)) .toList()))); } final container = new Container( margin: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 30.0), child: new Stack(children: <Widget>[ header, new Padding(padding: new EdgeInsets.only(top: 48.0), child: body), ])); if (Platform.isIOS) { return new Padding( padding: new EdgeInsets.only(top: 8.0), child: container); } return container; } Widget _textField() => new TextField( controller: query, autofocus: true, decoration: new InputDecoration( hintText: widget.hint, hintStyle: new TextStyle(color: Colors.black54, fontSize: 16.0), border: null), onChanged: search, ); } class GooglePlacesAutocompleteResult extends StatefulWidget { final ValueChanged<Prediction> onTap; GooglePlacesAutocompleteResult({this.onTap}); @override _GooglePlacesAutocompleteResult createState() => new _GooglePlacesAutocompleteResult(); } class _GooglePlacesAutocompleteResult extends State<GooglePlacesAutocompleteResult> { @override Widget build(BuildContext context) { final state = GooglePlacesAutocompleteWidget.of(context); assert(state != null); if (state.query.text.isEmpty || state.response == null || state.response.predictions.isEmpty) { final children = <Widget>[]; return new Stack(children: children); } return new PredictionsListView( predictions: state.response.predictions, onTap: widget.onTap); } } class PredictionsListView extends StatelessWidget { final List<Prediction> predictions; final ValueChanged<Prediction> onTap; PredictionsListView({@required this.predictions, this.onTap}); @override Widget build(BuildContext context) { return new ListView( children: predictions .map((Prediction p) => new PredictionTile(prediction: p, onTap: onTap)) .toList()); } } class PredictionTile extends StatelessWidget { final Prediction prediction; final ValueChanged<Prediction> onTap; PredictionTile({@required this.prediction, this.onTap}); @override Widget build(BuildContext context) { return new ListTile( leading: new Icon(Icons.location_on), title: new Text(prediction.description), onTap: () { if (onTap != null) { onTap(prediction); } }, ); } } Future<Prediction> showGooglePlacesAutocomplete( {@required BuildContext context, @required String apiKey, String hint = "Search", num offset, Location location, num radius, String language, List<String> types, List<Component> components, bool strictbounds, ValueChanged<PlacesAutocompleteResponse> onError}) { final builder = (BuildContext ctx) => new GooglePlacesAutocompleteWidget( apiKey: apiKey, language: language, components: components, types: types, location: location, radius: radius, strictbounds: strictbounds, offset: offset, hint: hint, onError: onError, ); return showDialog(context: context, builder: builder); } abstract class GooglePlacesAutocompleteState extends State<GooglePlacesAutocompleteWidget> { TextEditingController query; PlacesAutocompleteResponse response; GoogleMapsPlaces _places; bool searching; @override void initState() { super.initState(); query = new TextEditingController(text: ""); _places = new GoogleMapsPlaces(widget.apiKey); searching = false; } Future<Null> doSearch(String value) async { if (mounted && value.isNotEmpty) { setState(() { searching = true; }); final res = await _places.autocomplete(value, offset: widget.offset, location: widget.location, radius: widget.radius, language: widget.language, types: widget.types, components: widget.components, strictbounds: widget.strictbounds); if (res.errorMessage?.isNotEmpty == true || res.status == "REQUEST_DENIED") { onResponseError(res); } else { onResponse(res); } } else { onResponse(null); } } Timer _timer; Future<Null> search(String value) async { _timer?.cancel(); _timer = new Timer(const Duration(milliseconds: 300), () { _timer.cancel(); doSearch(value); }); } @override void dispose() { _timer?.cancel(); _places.dispose(); super.dispose(); } @mustCallSuper void onResponseError(PlacesAutocompleteResponse res) { if (mounted) { if (widget.onError != null) { widget.onError(res); } setState(() { response = null; searching = false; }); } } @mustCallSuper void onResponse(PlacesAutocompleteResponse res) { if (mounted) { setState(() { response = res; searching = false; }); } } }



6. After that create some util classes gps_util.dart, map_util.dart and google_place_util.dart.
  •  gps_util.dart  will get your current position and update to another aspect of the app.
gps_util.dart
import 'dart:async'; import 'package:flutter/services.dart'; import 'package:location/location.dart'; class GpgUtils { GpsUtilListener listener; Map<String, double> _startLocation; Map<String, double> _currentLocation; StreamSubscription<Map<String, double>> _locationSubscription; Location _location = new Location(); bool _permission = false; String error; bool currentWidget = true; GpgUtils(this.listener); void init() { initPlatformState(); _locationSubscription = _location.onLocationChanged().listen((Map<String,double> result) { _currentLocation = result; listener.onLocationChange(_currentLocation); }); } // Platform messages are asynchronous, so we initialize in an async method. initPlatformState() async { Map<String, double> location; // Platform messages may fail, so we use a try/catch PlatformException. try { _permission = await _location.hasPermission(); location = await _location.getLocation(); error = null; } on PlatformException catch (e) { if (e.code == 'PERMISSION_DENIED') { error = 'Permission denied'; } else if (e.code == 'PERMISSION_DENIED_NEVER_ASK') { error = 'Permission denied - please ask the user to enable it from the app settings'; } location = null; } _startLocation = location; listener.onLocationChange(_startLocation); } } abstract class GpsUtilListener { onLocationChange(Map<String, double> location); }
  • map_util.dart will manage google map methods. Here, we have created a method getDirectionSteps. It will take a source and destination param and get google route map steps by using google map API. Before using it, make sure you have enabled it from google console as discussed above.
map_util.dart
import 'package:flutter/material.dart'; import 'package:flutter_google_map_route/utils/gps_util.dart'; import 'package:flutter_google_map_route/map_screen.dart'; import 'package:flutter_google_map_route/model/route.dart'; import 'package:flutter_google_map_route/network/networ_util.dart'; import 'package:map_view/map_view.dart'; import 'package:map_view/polyline.dart'; class MapUtil implements GpsUtilListener { var staticMapProvider; CameraPosition cameraPosition; var location = new Location(0.0, 0.0); var zoomLevel = 18.0; MapView mapView; NetworkUtil network = new NetworkUtil(); GpgUtils gpgUtils; ScreenListener _screenListener; List<Location> ccc; MapUtil(this._screenListener); init() { mapView = new MapView(); gpgUtils = new GpgUtils(this); gpgUtils.init(); staticMapProvider = new StaticMapProvider("google_api_key"); } getDirectionSteps(double destinationLat, double destinationLng) { network .get("origin=" + location.latitude.toString() + "," + location.longitude.toString() + "&destination=" + destinationLat.toString() + "," + destinationLng.toString() + "&key=google_api_key") .then((dynamic res) { List<Steps> rr = res; print(res.toString()); ccc = new List(); for (final i in rr) { ccc.add(i.startLocation); ccc.add(i.endLocation); } mapView.onMapReady.listen((_) { mapView.setMarkers(getMarker(location.latitude,location.longitude,destinationLat,destinationLng)); mapView.addPolyline(new Polyline("12", ccc, width: 15.0)); }); _screenListener.dismissLoader(); showMap(); }).catchError((Exception error) => _screenListener.dismissLoader()); } List<Marker> getMarker(double scrLat,double scrLng,double desLat,double desLng) { List<Marker> markers = <Marker>[ new Marker("1", "My Location", scrLat, scrLng, color: Colors.amber), new Marker("2", "Destination", desLat, desLng, color: Colors.red), ]; return markers; } Uri getStaticMap() { return staticMapProvider.getStaticUri(getMyLocation(), zoomLevel.toInt(), height: 400, width: 900); } Location getMyLocation() { return location; } CameraPosition getCamera() { cameraPosition = new CameraPosition(getMyLocation(), zoomLevel); return cameraPosition; } showMap() { mapView.show( new MapOptions( mapViewType: MapViewType.normal, initialCameraPosition: getCamera(), showUserLocation: true, title: "Draw route"), toolbarActions: [new ToolbarAction("Close", 1)]); mapView.onToolbarAction.listen((id) { if (id == 1) { mapView.dismiss(); } }); } updateLocation(Location location) { this.location = location; } updateZoomLevel(double zoomLevel) { this.zoomLevel = zoomLevel; } @override onLocationChange(Map<String, double> currentLocation) { location = new Location(currentLocation["latitude"], currentLocation["longitude"]); _screenListener.updateScreen(location); } cameraUpdate(CameraPosition cameraPosition) { print("campera position changed $location"); } void manageMapProperties() { mapView.zoomToFit(padding: 100); mapView.onLocationUpdated.listen((location) => updateLocation(location)); mapView.onTouchAnnotation.listen((marker) => print("marker tapped")); mapView.onMapTapped.listen((location) => updateLocation(location)); mapView.onCameraChanged .listen((cameraPosition) => cameraUpdate(cameraPosition)); } }

  • google_place_util.dart  will get google place list from the server.
google_place_util.dart
import 'dart:async'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_google_map_route/flutter_google_places_autocomplete.dart'; import 'package:google_maps_webservice/places.dart'; class GooglePlaces { final homeScaffoldKey = new GlobalKey<ScaffoldState>(); final searchScaffoldKey = new GlobalKey<ScaffoldState>(); GoogleMapsPlaces _places = new GoogleMapsPlaces("google_api_key"); Location location; GooglePlacesListener _mapScreenState; GooglePlaces(this._mapScreenState); Future findPlace(BuildContext context) async { Prediction p = await showGooglePlacesAutocomplete( context: context, location: location, apiKey: "google_api_key", onError: (res) { homeScaffoldKey.currentState .showSnackBar(new SnackBar(content: new Text(res.errorMessage))); }, ); displayPrediction(p, homeScaffoldKey.currentState); } Future<Null> displayPrediction(Prediction p, ScaffoldState scaffold) async { if (p != null) { // get detail (lat/lng) PlacesDetailsResponse detail = await _places.getDetailsByPlaceId(p.placeId); final lat = detail.result.geometry.location.lat; final lng = detail.result.geometry.location.lng; _mapScreenState.selectedLocation( lat, lng, detail.result.formattedAddress); } } void updateLocation(double lat, double long) { location = new Location(lat, long); } } abstract class GooglePlacesListener { selectedLocation(double lat, double long, String address); }

7. To get route steps, we using Google API in this project. For fetch steps, we have created another util class network_util.dart.
network_util.dart
import 'dart:async'; import 'dart:convert'; import 'package:flutter_google_map_route/model/route.dart'; import 'package:http/http.dart' as http; class NetworkUtil { static final BASE_URL = "https://maps.googleapis.com/maps/api/directions/json?"; static NetworkUtil _instance = new NetworkUtil.internal(); NetworkUtil.internal(); factory NetworkUtil() => _instance; final JsonDecoder _decoder = new JsonDecoder(); Future<dynamic> get(String url) { return http.get(BASE_URL + url).then((http.Response response) { String res = response.body; int statusCode = response.statusCode; print("API Response: " + res); if (statusCode < 200 || statusCode > 400 || json == null) { res = "{\"status\":" + statusCode.toString() + ",\"message\":\"error\",\"response\":" + res + "}"; throw new Exception(res); } List<Steps> steps; try { steps = parseSteps(_decoder.convert(res)["routes"][0]["legs"][0]["steps"]); } catch (e) { throw new Exception(res); } return steps; }); } List<Steps> parseSteps(final responseBody) { var list = responseBody.map<Steps>((json) => new Steps.fromJson(json)).toList(); return list; } }

8. To parse the response of Google API,  we have created a POJO model class.

steps.dart
import 'package:map_view/location.dart'; class Steps { Location startLocation; Location endLocation; Steps({this.startLocation, this.endLocation}); factory Steps.fromJson(Map<String, dynamic> json) { return new Steps( startLocation: new Location( json["start_location"]["lat"], json["start_location"]["lng"]), endLocation: new Location( json["end_location"]["lat"], json["end_location"]["lng"])); } }

Now merge all the code and put google API key.  If you have followed the article carefully, you can see the app running very smoothly as shown in the above video demo. But if you are facing any problem. You can get the working project from Github. 


Source Code               Flutter firebse storage apk

Flutter team has published a google map widget.  Check it here. Flutter - Google map widget plugin

Before run the downloaded project code, make sure. You have replaced google_api_key with your key in Android manifest, map_util.dart, and google_place_util.dart. If still, you have any quires, please feel free to ask it from below comment section.
 

Share:

15 comments:

  1. FAILURE: Build failed with an exception.

    * What went wrong:
    Execution failed for task ':app:preDebugBuild'.
    > Android dependency 'com.android.support:support-fragment' has different version for the compile (26.1.0) and runtime (27.1.1) classpath. You should manually set the same version via DependencyResolution

    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

    * Get more help at https://help.gradle.org

    BUILD FAILED in 4s
    Finished with error: Gradle task assembleDebug failed with exit code 1

    ReplyDelete
    Replies
    1. We have updated the code. Get it from Github.com

      Delete
  2. Hii I am new in flutter is there proper document and answer so I can implement in my project
    I want to make root between two marker and and show multiple marker on map

    ReplyDelete
    Replies
    1. Hey, Flutter team working for it.

      Delete
    2. Is there any information, about when it can be expected to be ready?

      Delete
    3. There is no update regarding this. Tell us your requirements. We'll guide you.

      Delete
  3. Hi! I've cloned your github repository for this article, added all the required updates. Then I'm trying to run the application, but in console see the following error:

    ...flutter/.pub-cache/hosted/pub.dartlang.org/map_view-0.0.14/android/src/main/kotlin/com/apptreesoftware/mapview/MapViewPlugin.kt: (178, 66): Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type Map?


    FAILURE: Build failed with an exception.

    * What went wrong:
    Execution failed for task ':map_view:compileDebugKotlin'.
    > Compilation error. See log for more details

    Can you please suggest the solution for this error.

    ReplyDelete
    Replies
    1. For people having this issue.

      1. Open the Android project and go to the MapView module, then select MapViewPlugin.kt inside the java folder (This should be the file path: .pub-cache\hosted\pub.dartlang.org\map_view-0.0.14\android\src\main\kotlin\com\apptreesoftware\mapview)

      2. If you are using Android Studio you will already see red warnings. Go to line 168 where you'll find val cameraDict = mapOptions["cameraPosition"] as Map

      3. Change it to this val cameraDict = mapOptions!!["cameraPosition"] as Map

      Now it should work.

      Delete
    2. Hello sir,

      I have a same problem. also try above solution but i getting the error.
      my error is :

      e: C:\Flutter\flutter\.pub-cache\hosted\pub.dartlang.org\map_view-0.0.14\android\src\main\kotlin\com\apptreesoftware\mapview\MapViewPlugin.kt: (168, 34): Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type Map?
      e: C:\Flutter\flutter\.pub-cache\hosted\pub.dartlang.org\map_view-0.0.14\android\src\main\kotlin\com\apptreesoftware\mapview\MapViewPlugin.kt: (171, 36): Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type Map?
      e: C:\Flutter\flutter\.pub-cache\hosted\pub.dartlang.org\map_view-0.0.14\android\src\main\kotlin\com\apptreesoftware\mapview\MapViewPlugin.kt: (172, 40): Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type Map?
      e: C:\Flutter\flutter\.pub-cache\hosted\pub.dartlang.org\map_view-0.0.14\android\src\main\kotlin\com\apptreesoftware\mapview\MapViewPlugin.kt: (173, 37): Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type Map?
      e: C:\Flutter\flutter\.pub-cache\hosted\pub.dartlang.org\map_view-0.0.14\android\src\main\kotlin\com\apptreesoftware\mapview\MapViewPlugin.kt: (174, 31): Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type Map?
      e: C:\Flutter\flutter\.pub-cache\hosted\pub.dartlang.org\map_view-0.0.14\android\src\main\kotlin\com\apptreesoftware\mapview\MapViewPlugin.kt: (175, 28): Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type Map?
      e: C:\Flutter\flutter\.pub-cache\hosted\pub.dartlang.org\map_view-0.0.14\android\src\main\kotlin\com\apptreesoftware\mapview\MapViewPlugin.kt: (177, 21): Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type Map?
      e: C:\Flutter\flutter\.pub-cache\hosted\pub.dartlang.org\map_view-0.0.14\android\src\main\kotlin\com\apptreesoftware\mapview\MapViewPlugin.kt: (178, 66): Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type Map?

      FAILURE: Build failed with an exception.

      * What went wrong:
      Execution failed for task ':map_view:compileDebugKotlin'.
      > Compilation error. See log for more details

      * Try:
      Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

      * Get more help at https://help.gradle.org

      BUILD FAILED in 13s
      Running Gradle task 'assembleDebug'...
      Running Gradle task 'assembleDebug'... Done 14.0s
      Gradle task assembleDebug failed with exit code 1

      Delete
    3. These google map plugin is deprecated now. Please check new official Google map widget that is developed by Flutter.

      Delete
  4. Hey bro.. how to get direction step multiple time and draw route multiple marker point like this
    https://dl2.pushbulletusercontent.com/a2Yf8fqyfkhJrJ3bPVf2rSMGhq8zfHg0/Screenshot_20180727-021319.png
    for native i solved but flutter @#$%&*?? please help me!

    ReplyDelete
  5. how can this be done from the updated google_map_flutter plugin??

    ReplyDelete
  6. Please create same tutorial for Flutter google map widget.

    ReplyDelete
  7. good day, is there a way we can let google direct people using it. I am talking navigation?
    Please help.

    ReplyDelete

WE'RE SOCIAL

Promotional

  • Cover art Blend

    Blend app is very advanced app there are lots of features like shayari, status, chat, feed....

Categories