Im having trouble using a custom marker in my GoogleMaps project with flutter. I get this error when the map screen loads
Exception has occurred.
LateError (LateInitializationError: Field 'myMarker' has not been initialized.)
I tried without using late and it says myMarker has to be initialized so I declared it as late and then initialized it in the initState. That didn't work so I tried with a nullable ? and that did not work either. Any help would be appreciated.
Thanks
import 'dart:async';
import 'dart:developer';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:location/location.dart';
import 'dart:math' as math;
import './main.dart' as main;
import './variables.dart' as variables;
import './methods.dart' as methods;
import './mapvariables.dart' as mapVar;
import './marker_information.dart' as markerInfo;
class MapScreen extends StatefulWidget {
const MapScreen({Key? key}) : super(key: key);
#override
_MapScreenState createState() => _MapScreenState();
}
class _MapScreenState extends State<MapScreen> {
Completer<GoogleMapController> _controllerGoogleMap = Completer();
late GoogleMapController newGoogleMapController;
Position? currentPosition;
var geoLocator = Geolocator();
final double dcheck = 0.00014128694207108202;
var location = new Location();
late BitmapDescriptor myMarker;
#override
void initState() {
super.initState();
setMarker();
}
void setMarker() async {
myMarker = await BitmapDescriptor.fromAssetImage(
ImageConfiguration(), 'loginlogo.png');
}
checkpermission_location() async {
var locationStatus = await Permission.location.status;
print(locationStatus);
if (!locationStatus.isGranted) {
print("gr");
print(await Permission.location.value);
await Permission.location.request();
checkpermission_location();
}
if (!locationStatus.isDenied) {
print('de');
await Permission.location.request();
checkLocation();
}
}
void checkClue(var x, var y, markerInfo.ClueLocation marker) {
double distance = methods.distance(marker.lat, marker.long, x, y);
log("distance: $distance");
if ((distance < dcheck)) {
variables.dialogVis = true;
if ((variables.dialogVis) && (marker.compl == false)) {
mapVar.showAlertDialog(context, marker);
variables.dialogVis = false;
marker.compl = true;
}
}
}
void checkLocation() {
location.onLocationChanged.listen((LocationData currentLocation) {
var lat = currentLocation.latitude;
var long = currentLocation.longitude;
checkClue(lat, long, markerInfo.newHamCollege);
checkClue(lat, long, markerInfo.coeFen);
checkClue(lat, long, markerInfo.mathematicalBridge);
checkClue(lat, long, markerInfo.graveYard);
checkClue(lat, long, markerInfo.archeologicalMuseum);
checkClue(lat, long, markerInfo.addenbrokesHospital);
checkClue(lat, long, markerInfo.stMarysBellTower);
checkClue(lat, long, markerInfo.trinityStreet);
checkClue(lat, long, markerInfo.viewOfTheBridgeOfSighs);
});
}
//Initial camera position when maps first load
static const _initalCameraPosition = CameraPosition(
target: LatLng(52.2053, 0.1218),
zoom: 11.5,
);
Marker makeMarker(markerInfo.ClueLocation marker) {
return (Marker(
markerId: MarkerId(marker.title),
infoWindow: InfoWindow(title: marker.title),
icon: myMarker,
position: LatLng(marker.lat, marker.long),
onTap: () {
if (marker.compl) {
mapVar.showAlertDialog(context, marker);
}
}));
}
//Google map widget
#override
Widget build(BuildContext context) {
//Checks if mapAcess is true
if (variables.mapAccess) {
var currentlocation = location.getLocation();
return Scaffold(
body: GoogleMap(
onMapCreated: (GoogleMapController controller) {
controller.setMapStyle(mapVar.mapStyle);
checkpermission_location();
_controllerGoogleMap.complete(controller);
newGoogleMapController = controller;
},
mapType: MapType.normal,
myLocationButtonEnabled: true,
zoomControlsEnabled: true,
myLocationEnabled: true,
zoomGesturesEnabled: true,
markers: {
//Markers located in the variables.dart file
makeMarker(markerInfo.newHamCollege),
makeMarker(markerInfo.coeFen),
makeMarker(markerInfo.mathematicalBridge),
makeMarker(markerInfo.graveYard),
makeMarker(markerInfo.archeologicalMuseum),
//6.??? Waiting for update from Konstantin
makeMarker(markerInfo.addenbrokesHospital),
makeMarker(markerInfo.stMarysBellTower),
makeMarker(markerInfo.trinityStreet),
makeMarker(markerInfo.viewOfTheBridgeOfSighs),
},
initialCameraPosition: _initalCameraPosition,
),
);
}
//Refuses access if 10 Digit key is not provided
return Scaffold(
body: Center(
child: Text('You do not have access to the map, please login')));
}
}
You pretty much have it the same way I do it; the way I've done it is as follows:
Set up the BitmapDescriptor as a nullable property at the top of your state class, as well as I create a markers Set:
Set<Marker>? _markers = <Marker>{};
BitmapDescriptor? myMarker
I create an async method that I run at the beginning of the build method (I do it in the build method because I need the build context sometimes), that asynchronously loads the bitmaps, as in:
void setMarkerIcon() async {
myMarker = await BitmapDescriptor.fromAssetImage(
const ImageConfiguration(size: Size(50, 50)),'loginlogo.png');
}
Then in the build method I just call it:
#override
Widget build(BuildContext context) {
// you can call it here
setMarkerIcons();
return Scaffold(
body: GoogleMap(
markers: _markers!,
onMapCreated: (GoogleMapController ctrl) {
// here after map is loaded, I generate the markers
generateMarkers();
}
)
);
BONUS:
Then as shown above, upon the map getting created, I can go ahead and use the custom markers, based on a list of locations, as such:
void generateMarkers() {
var localMarkers = <Marker>{};
for(var location in locationsList!) {
localMarkers.add(
Marker(
markerId: MarkerId(location.id!),
position: LatLng(location.lat!, location.lng!),
icon: myMarker
)
);
}
if (mounted) {
setState(() {
_markers = localMarkers;
});
}
}
Related
The application that I'm trying to create required the creation of a route that has destinations between the starting and ending point, between the beginning and end provided in the getRouteBetweenCoordinates, I need a way to add a custom Latlong pair that must travel through, instead of finding the quickest route, I need it to route between all points that I provided while still following the road (not just a direct line).
The only method that I could come up with is recalling the setPolyLines function for each stretch that makes up the total route. While this method could get the desired result, it required making multiple API calls, ideally, the entirety of the custom route would be loaded upon that first directions API call.
Here is the code that I'm working with, Is there an easier solution to this problem that I missed? This may be very obvious but I'm new with google maps integration so sorry if that's the case.
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:flutter_polyline_points/flutter_polyline_points.dart';
//new polyline between each destination
class Tour extends StatefulWidget {
const Tour({Key? key}) : super(key: key);
#override
_TourState createState() => _TourState();
}
class _TourState extends State<Tour> {
late GoogleMapController mapController;
//poly line variables
Set<Polyline> _polyLine = Set<Polyline>();
List<LatLng> polylineCordinates = [];
late PolylinePoints polylinePoints;
//starting location
static const _start =
CameraPosition(target: LatLng(48.696985, -122.905595), zoom: 17.0);
//METHODS
void _onMapCreated(GoogleMapController controller) {
mapController = controller;
//TODO: provide with start and end point for specific line, end of last ==
//start of next
setPolyLines(PointLatLng(48.696985, -122.905595),
PointLatLng(48.657421, -122.917412));
setPolyLines(PointLatLng(48.657421, -122.917412),
PointLatLng(48.644983, -122.944760));
}
void setPolyLines(PointLatLng start, PointLatLng end) async {
//polyline result DT is a collection of latlng following roads
PolylineResult result = await polylinePoints.getRouteBetweenCoordinates(
"MY API KEY IS HERE",
//route start
start,
//route end
end);
//list of latlng pairs in order of exectecution
//this is preparing the drawing of the line, the set state plots it out
if (result.status == 'OK') {
result.points.forEach((PointLatLng point) {
polylineCordinates.add(LatLng(point.latitude, point.longitude));
});
}
setState(() {
_polyLine.add(Polyline(
width: 10,
//set id to
polylineId: PolylineId("route"),
color: Color(0xFF00BFA6),
points: polylineCordinates));
});
}
#override
void initState() {
polylinePoints = PolylinePoints();
}
#override
void dispose() {
mapController.dispose();
super.dispose();
}
//upon call, modal sheet toggles from the bottom of screen
modalSheet() {
showModalBottomSheet(
context: context,
builder: (context) {
return Column(
children: [
Container(
height: 200,
color: Colors.amber,
),
Container(
height: 100,
color: Colors.blue,
)
],
);
});
}
//adjusts camera position to the _start location
center() {
mapController.animateCamera(CameraUpdate.newCameraPosition(_start));
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: GoogleMap(
polylines: _polyLine,
myLocationButtonEnabled: false,
zoomControlsEnabled: false,
onMapCreated: _onMapCreated,
initialCameraPosition: _start),
floatingActionButton: FloatingActionButton(
onPressed: () => center(), child: Icon(Icons.add)),
);
}
}
You can use wayPoints parameter of getRouteBetweenCoordinates method which accepts a list of PolylineWayPoint (List<PolylineWayPoint>).
PolylineResult result = await polylinePoints.getRouteBetweenCoordinates(
googleAPiKey,
PointLatLng(48.696985, -122.905595),
PointLatLng(48.644983, -122.944760),
wayPoints: [PolylineWayPoint(location: "48.657421,-122.917412")]);
Please see the image below for the result using your sample code.
I have a sample app that I am building that fetches multiple markers from Firestore and displays them on Google Maps.
The issue is that the changes (markers added/deleted/updated) aren't displayed in real time since it only rebuilds in init state. I think that I could use Stream Builder to listen to the changes and update them in real time.
I am not sure how to do it with Google Maps and Firestore, since the syntax is kinda weird with snapshots, I tried many ways, but not successful. Here's my code:
#override
void initState() {
populateMarkers();
super.initState();
}
populateMarkers() {
FirebaseFirestore.instance.collection('marker').get().then((documents) {
if (documents.docs.isNotEmpty) {
for (int i = 0; i < documents.docs.length; i++) {
initMarker(
documents.docs[i].data(), documents.docs[i].id);
}
}
});
}
void initMarker(request, requestId) {
var markerIdVal = requestId;
final MarkerId markerId = MarkerId(markerIdVal);
//creating new markers
final Marker marker = Marker(
markerId: markerId,
position:
LatLng(request['location'].latitude, request['location'].longitude),
infoWindow:
InfoWindow(title: request['name'], snippet: request['description']),
onTap: () => print('Test'),
);
setState(() {
markers[markerId] = marker;
//print(markerId);
});
}
Widget loadMap() {
return GoogleMap(
markers: Set<Marker>.of(markers.values),
mapType: MapType.normal,
initialCameraPosition:
CameraPosition(target: LatLng(43.8031287, 20.453008), zoom: 12.0),
onMapCreated: onMapCreated,
// },
);
}
and in the buider, I just call loadMap() function as the body. As I mentioned, this works fine, but I would like to use Stream Builder for these functions to update in real time. Any ideas how to do it?
This thread has a similar issue, but I feel it's not the best way to do it:
Flutter - Provide Real-Time Updates to Google Maps Using StreamBuilder
Here is the full code in case someone wants to test it out:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
class MapScreen extends StatefulWidget {
#override
_MapScreenState createState() => _MapScreenState();
}
class _MapScreenState extends State<MapScreen> {
Map<MarkerId, Marker> markers = <MarkerId, Marker>{}; //--> google
GoogleMapController _controller;
#override
void initState() {
populateMarkers();
super.initState();
}
onMapCreated(GoogleMapController controller) async {
_controller = controller;
String value = await DefaultAssetBundle.of(context)
.loadString('assets/map_style.json');
_controller.setMapStyle(value);
}
populateMarkers() {
FirebaseFirestore.instance.collection('marker').get().then((documents) {
if (documents.docs.isNotEmpty) {
for (int i = 0; i < documents.docs.length; i++) {
initMarker(
documents.docs[i].data(), documents.docs[i].id); //maybe error
//documents.docs[i].data, documents.docs[i].id
}
}
});
}
void initMarker(request, requestId) {
var markerIdVal = requestId;
final MarkerId markerId = MarkerId(markerIdVal);
//creating new markers
final Marker marker = Marker(
markerId: markerId,
position:
LatLng(request['location'].latitude, request['location'].longitude),
infoWindow:
InfoWindow(title: request['name'], snippet: request['description']),
onTap: () => print('Test'),
);
setState(() {
markers[markerId] = marker;
//print(markerId);
});
}
Widget loadMap() {
return GoogleMap(
// markers: markers.values.toSet(),
markers: Set<Marker>.of(markers.values),
mapType: MapType.normal,
initialCameraPosition:
CameraPosition(target: LatLng(44.8031267, 20.432008), zoom: 12.0),
onMapCreated: onMapCreated,
cameraTargetBounds: CameraTargetBounds(LatLngBounds(
northeast: LatLng(44.8927468, 20.5509553),
southwest: LatLng(44.7465138, 20.2757283))),
mapToolbarEnabled: false,
// onMapCreated: (GoogleMapController controller) {
// _controller = controller;
// },
);
}
void dispose() {
_controller.dispose();
super.dispose();
}
//-----------------------------------
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('App'),
centerTitle: true,
backgroundColor: Colors.blue[700],
actions: [
// ElevatedButton(
// onPressed: () => refresh(),
// child: Text('REFRESH'),
// )
],
),
body: loadMap(),
);
}
}
So you want to subscribe to a stream coming from a firestore collection, and use this data to update markers on a map in real-time, is that right?
Please note that you absolutely need to separate your services from your widgets, or you'll end up quickly with a jumbled mess of a code.
In one file you have the class defining access to your database (such as API calls, or Firestore in this case). ANY write or read with Firestore will go through this service.
class FirestoreService {
FirestoreService._();
static final instance = FirestoreService._();
Stream<List<T>> collectionStream<T>({
required String path,
required T Function(Map<String, dynamic> data, String documentID) builder,
}) {
Query query = FirebaseFirestore.instance.collection(path);
final Stream<QuerySnapshot> snapshots = query.snapshots();
return snapshots.map((snapshot) {
final result = snapshot.docs
.map((snapshot) =>
builder(snapshot.data() as Map<String, dynamic>, snapshot.id))
.where((value) => value != null)
.toList();
return result;
});
}
}
In another file, you'll have the repository service, that contains the CRUD operations. Each operation makes a call to the DB service (defined in the previous step) and uses the objects's serialization (toJson, send to DB) or parsing (fromJson, get from DB) methods.
class MarkersRepo {
final _service = FirestoreService.instance;
Stream<List<Marker>> getMarkers() {
return _service.collectionStream(
path: 'marker',
builder:(json, docId){
return Marker.fromJson(json);
}
);
}
}
In another file, you define your Marker object model with the serialization and parsing methods. Please don't use strings to access directly the document properties in your code, as that is error-prone and again will cause messy code. Instead, you define those once and for all in the object model.
class Marker{
//properties of the object such as location, name and description
//toJson and fromJson methods
}
And finally in your widget file, as you noted yourself you are only reading the document once, in the initstate, so the view does not update. Instead, one simple option is to have a StreamBuilder inside your build method, extract the markers there and then display them:
Widget build(Buildcontext context){
return StreamBuilder(
stream: MarkersRepos().getMarkers(),
builder:(context, snapshot){
//check for connection state and errors, see streambuilder documentation
final List<Marker> markers = snapshot.data;
return loadMap(markers);
}
);
}
EDIT: added more details
I have a problem with location and google maps in flutter: I'm building an app whom first screen is a map from Google and I'm trying to use user location as "initialCameraPosition" of the map. The problem is that when I start the application when the location already on, everything is okay, I see the map clearly and also the user location is okay. Instead, when I start the application with the location off, even though I able the location when the app starts then I cannot see the map anymore and it seems that the location is null.
Here's my code (map screen):
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:provider/provider.dart';
import 'package:stabia_go/location.dart';
import 'package:stabia_go/markers.dart';
class GoogleMapScreen extends StatefulWidget {
#override
_GoogleMapScreenState createState() => _GoogleMapScreenState();
}
class _GoogleMapScreenState extends State<GoogleMapScreen> {
Set<Marker> _markers = {};
void _onMapCreated(GoogleMapController controller) {
setState(() {
_markers.addAll(markers);
});
}
#override
void initState() {
super.initState();
Provider.of<LocationProvider>(context, listen: false).initialization();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text('Percorso Suggerito'),
),
body: googleMapUI(),
);
}
Widget googleMapUI() {
return Consumer<LocationProvider>(builder: (consumerContext, model, child) {
if (model.locationPosition != null) {
return GoogleMap(
markers: _markers,
initialCameraPosition:
CameraPosition(target: model.locationPosition, zoom: 15),
myLocationEnabled: true,
myLocationButtonEnabled: true,
onMapCreated: _onMapCreated,
);
}
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
});
}
}
Here's the code of the location file:
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:location/location.dart';
class LocationProvider with ChangeNotifier {
Location _location;
Location get location => _location;
LatLng _locationPosition;
LatLng get locationPosition => _locationPosition;
LocationProvider() {
_location = new Location();
}
initialization() async {
await getUserLocation();
}
getUserLocation() async {
bool serviceEnabled;
PermissionStatus permissionGranted;
serviceEnabled = await location.serviceEnabled();
if (!serviceEnabled) {
serviceEnabled = await location.requestService();
if (!serviceEnabled) {
return;
}
}
permissionGranted = await location.hasPermission();
if (permissionGranted == PermissionStatus.denied) {
permissionGranted = await location.requestPermission();
if (permissionGranted != PermissionStatus.granted) {
return;
}
}
location.onLocationChanged.listen(
(LocationData currentLocation) {
_locationPosition = LatLng(
currentLocation.latitude,
currentLocation.longitude,
);
print(_locationPosition);
notifyListeners();
},
);
}
}
Where's my mistake? I'm using Location, Provider and Google Maps flutter packages
Try to check for location access when your app is launching. if permission is denied the redirect user to allow location access. if user allow then everything will work fine else user deny access then show a hard coded location.
everyone.
I'm trying to develop a PWA with flutter 2.2.1 that shows a map using Mapbox_gl and displays the user current location using Geolocator.
So far everything works as expected while debuging the app, but when I run:
flutter build
or
flutter build --release
and then run
firebase deploy
the site gets uploaded, the map shows as intended and it asks for permissions but the user's location is never shown and Google Chrome's Console throws this error:
Uncaught TypeError: m.gfR is not a function
at Object.avh (main.dart.js:20405)
at main.dart.js:65755
at aiD.a (main.dart.js:5853)
at aiD.$2 (main.dart.js:34394)
at ahm.$1 (main.dart.js:34386)
at Rx.o1 (main.dart.js:35356)
at adi.$0 (main.dart.js:34770)
at Object.tQ (main.dart.js:5975)
at a5.mn (main.dart.js:34687)
at ada.$0 (main.dart.js:34731)
Here's the code I'm using on flutter:
mapbox.dart
import 'dart:async';
import 'dart:io';
import 'dart:math';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:geolocator/geolocator.dart';
import 'package:kkc/main.dart';
import 'package:mapbox_gl/mapbox_gl.dart';
import 'package:kkc/services/location_service.dart';
class Mapbox extends StatefulWidget {
const Mapbox();
#override
State createState() => MapboxState();
}
class MapboxState extends State<Mapbox> {
final Random _rnd = new Random();
Position? _currentLocation;
LatLng _currentCoordinates = new LatLng(0,0);
final List<_PositionItem> _positionItems = <_PositionItem>[];
StreamSubscription<Position>? _positionStreamSubscription;
late MapboxMapController _mapController;
List<Marker> _markers = [];
List<_MarkerState> _markerStates = [];
CameraPosition _kInitialPosition = CameraPosition(
target: LatLng(19.4274418, -99.1682147),
zoom: 18.0,
tilt: 70,
);
void _addMarkerStates(_MarkerState markerState) {
_markerStates.add(markerState);
}
void _onMapCreated(MapboxMapController controller) {
_mapController = controller;
controller.addListener(() {
if (controller.isCameraMoving) {
_updateMarkerPosition();
}
});
}
void _onStyleLoadedCallback() {
_updateMarkerPosition();
}
void _onCameraIdleCallback() {
_updateMarkerPosition();
}
void _updateMarkerPosition() {
final coordinates = <LatLng>[];
for (final markerState in _markerStates) {
coordinates.add(markerState.getCoordinate());
}
_mapController.toScreenLocationBatch(coordinates).then((points) {
_markerStates.asMap().forEach((i, value) {
_markerStates[i].updatePosition(points[i]);
});
});
}
void _addMarker(Point<double> point, LatLng coordinates) {
setState(() {
_markers.add(Marker(_rnd.nextInt(100000).toString(), coordinates, point, _addMarkerStates));
});
}
#override
void initState() {
super.initState();
_getCurrentLocation();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: Stack(children: [
MapboxMap(
accessToken: Kukulcan.MAPBOX_ACCESS_TOKEN,
trackCameraPosition: true,
onMapCreated: _onMapCreated,
onCameraIdle: _onCameraIdleCallback,
onStyleLoadedCallback: _onStyleLoadedCallback,
initialCameraPosition: _kInitialPosition,
),
IgnorePointer(
ignoring: true,
child: Stack(
children: _markers,
))
]),
);
}
void _getCurrentLocation() async {
_currentLocation = await LocationService.startLocationService();
_currentCoordinates = new LatLng(_currentLocation!.latitude,_currentLocation!.longitude);
await _mapController.animateCamera(CameraUpdate.newLatLng(_currentCoordinates));
_addMarker(new Point(1, 1), _currentCoordinates);
if (_positionStreamSubscription == null) {
final positionStream = Geolocator.getPositionStream();
_positionStreamSubscription = positionStream.handleError((error) {
_positionStreamSubscription?.cancel();
_positionStreamSubscription = null;
}).listen((position) => setState(() => _positionItems.add(
_PositionItem(_PositionItemType.position, position.toString()))));
_positionStreamSubscription?.pause();
}
}
}
class Marker extends StatefulWidget {
final Point _initialPosition;
LatLng _coordinate;
final void Function(_MarkerState) _addMarkerState;
Marker(
String key, this._coordinate, this._initialPosition, this._addMarkerState)
: super(key: Key(key));
#override
State<StatefulWidget> createState() {
final state = _MarkerState(_initialPosition);
_addMarkerState(state);
return state;
}
}
class _MarkerState extends State with TickerProviderStateMixin {
final _iconSize = 80.0;
Point _position;
_MarkerState(this._position);
#override
Widget build(BuildContext context) {
var ratio = 1.0;
//web does not support Platform._operatingSystem
if (!kIsWeb) {
// iOS returns logical pixel while Android returns screen pixel
ratio = Platform.isIOS ? 1.0 : MediaQuery.of(context).devicePixelRatio;
}
return Positioned(
left: _position.x / ratio - _iconSize / 2,
top: _position.y / ratio - _iconSize / 2,
child: Image.asset('assets/img/pin.png', height: _iconSize));
}
void updatePosition(Point<num> point) {
setState(() {
_position = point;
});
}
LatLng getCoordinate() {
return (widget as Marker)._coordinate;
}
}
enum _PositionItemType {
permission,
position,
}
class _PositionItem {
_PositionItem(this.type, this.displayValue);
final _PositionItemType type;
final String displayValue;
}
Does anyone have an idea on what's the problem?
Cheers!
Anyway the solution i found is to use --no-sound-null-safety argument as stated by geolocat documentation
I quote:
NOTE: due to a bug in the dart:html library the web version of the Geolocator plugin does not work with sound null safety enabled and compiled in release mode. Running the App in release mode with sound null safety enabled results in a Uncaught TypeError (see issue #693). The current workaround would be to build your App with sound null safety disabled in release mode:
In my flutter application only the Markers are visible in the Map screen but path is not displaying via polylines ,I have set a debugger point and following if statement is not executed .
if(result.status == 'OK'){
result.points.forEach((PointLatLng point){
polylineCoordinates.add(LatLng(point.latitude,point.longitude));
});
please refer the below code above is extracted form below code.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_polyline_points/flutter_polyline_points.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
class GooglePolylines extends StatefulWidget {
GooglePolylines({Key key}) : super(key: key);
#override
GooglePolyline createState() => GooglePolyline();
}
class GooglePolyline extends State<GooglePolylines>{
GoogleMapController mapController;
double _originLatitude = 26.48424, _originLongitude = 50.04551;
double _destLatitude = 26.46423, _destLongitude = 50.06358;
Map<MarkerId, Marker> markers = {};
String googleAPiKey = "MY KEY";
Set <Polyline> _polyLines = Set<Polyline>();
List <LatLng> polylineCoordinates = [];
PolylinePoints polylinePoints ;
#override
void initState() {
super.initState();
polylinePoints =PolylinePoints();
/// origin marker
_addMarker(LatLng(_originLatitude, _originLongitude), "origin",
BitmapDescriptor.defaultMarker);
/// destination marker
_addMarker(LatLng(_destLatitude, _destLongitude), "destination",
BitmapDescriptor.defaultMarkerWithHue(90));
// setPolyLines();
// _getPolyline();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: GoogleMap(
initialCameraPosition: CameraPosition(
target: LatLng(_originLatitude, _originLongitude), zoom: 15),
myLocationEnabled: true,
tiltGesturesEnabled: true,
compassEnabled: true,
scrollGesturesEnabled: true,
zoomGesturesEnabled: true,
onMapCreated: _onMapCreated,
markers: Set<Marker>.of(markers.values),
//rendering polyLines by map
polylines: _polyLines,
)),
);
}
void _onMapCreated(GoogleMapController controller) async {
mapController = controller;
setPolyLines();
}
_addMarker(LatLng position, String id, BitmapDescriptor descriptor) {
MarkerId markerId = MarkerId(id);
Marker marker =
Marker(markerId: markerId, icon: descriptor, position: position);
markers[markerId] = marker;
}
void setPolyLines() async {
PolylineResult result = await polylinePoints.getRouteBetweenCoordinates(
googleAPiKey,
PointLatLng( _originLatitude, _originLongitude),
PointLatLng(_destLatitude, _destLongitude ),
travelMode: TravelMode.driving,
);
if(result.status == 'OK'){
result.points.forEach((PointLatLng point){
polylineCoordinates.add(LatLng(point.latitude,point.longitude));
});
setState((){
_polyLines.add(Polyline(
visible: true,
width:10,
polylineId:PolylineId('polyLineTest'),
color: Colors.blue,
points:polylineCoordinates
));
});
}
}
}
In the API section google cloud platform console , all the applied requests are shown as errors.
I tried your code using my own API key and I was able to show the polyline (Please see screenshot below). It looks like the issue is with your own API key. To solve the issue, make sure that:
You are using a valid API key and
the Directions API is enabled in your project and
your project is linked to a valid billing account
Check out this documentation for more info.