MapController and google map marker not working - google-maps

So am using the google map marker in flutter, but it not working, instead it showing "Undefined name 'mapController'.
Try correcting the name to one that is defined, or defining the name"
Here is my code:
void _onMapCreated(GoogleMapController controller){
setState(() {
mapController = controller;
});
}
}
_addMarker() {
var marker = MarkerOptions(
position: mapController.cameraPosition.target,
icon: BitmapDescriptor.defaultMarker,
infoWindowText: InfoWindowText('Magic Marker', '🍄🍄🍄')
);
mapController.addMarker(marker);
}
These are the dependencies used:
geoflutterfire: "^2.0.2"
location: "^1.4.1"
google_maps_flutter: "^0.2.0"
What am I doing wrong?

Related

Flutter: How to animate the camera of Google Maps

I'm trying to build an app that loads a GoogleMap(), then after getting the user latitude and longitude moves to the that specific location.
I came up with this idea (code below), but it works only if I restart the app and if I don't it gives error: animateCamera was called on null.
How is it possible ? and how can i fix it ?
Thanks for answering :D
...
var mapController;
...
GoogleMap createMap() {
var initMap = GoogleMap(
onMapCreated: onMapCreated,
initialCameraPosition:
CameraPosition(target: LatLng(47.290542, 8.322641), zoom: 6.7),
);
return initMap;
}
...
void onMapCreated(controller) {
mapController = controller;
}
...
void moveCameraToUserLocation(searchedLocation2) async {
var location = await Geocode().getLatLng(searchedLocation2);
print("moving to: $location");
mapController.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(
target: location,
zoom: 20,
),
),
);
...
build(context) {
return Scaffold(
body: createMap(),
...
Based on how you describe the problem, it looks like you are only calling the animate function as the map loads.
I suggest that you create a button that would handle and trigger the animate function and move the camera to the device location whenever tapped.
The following code snippet uses a ClipOval button and inside the OnTap() event you can call the method to get the device current location which will be triggered whenever the button is tapped.
ClipOval(
child: Material(
color: Colors.green[100], // button color
child: InkWell(
splashColor: Colors.green, // inkwell color
child: SizedBox(
width: 56,
height: 56,
child: Icon(Icons.my_location),
),
onTap: () {
// Add methods here that will be called whenever the button is tapped
mapController.animateCamera(CameraUpdate.newCameraPosition(CameraPosition(
target: LatLng(_currentPosition.latitude, _currentPosition.longitude),
zoom: 17.0)));
setState(() {
allMarkers.add(Marker(
markerId: MarkerId('Current Position'),
draggable: false,
position:
LatLng(_currentPosition.latitude, _currentPosition.longitude)));
});
},
),
),
)
Probably you are calling moveCameraToUserLocation function before map is created. From this part of the code I cannot se when you call thi function but my guess is that you call it from initstate. If you want to call this function immediately after widget is created move it to onMapCreated.
void onMapCreated(controller) {
mapController = controller;
moveCameraToUserLocation();
}

Difference between camera animation and user camera movement

I'm currently using GoogleMap in Flutter. I also use the clustering_google_maps package to display clusters of markers. The default behavior of this plugin is that every camera movement triggers an update of all the markers and clusters. This behavior takes into account the user zoom in/out and translation.
I added a feature where the camera moves according to the user's location whith the location package.
initPlatformState() async {
// Wait for the Completer to complete and return the GoogleMap Controler
mapController = await _controller.future;
// Set controller for the ClusteringHelper
clusteringHelper.mapController = mapController;
// Get database and update markers
clusteringHelper.database = await DBHelper().database;
clusteringHelper.updateMap();
// Set parameters for location Service
await _locationService.changeSettings(
accuracy: LocationAccuracy.HIGH, interval: 1000);
try {
bool serviceStatus = await _locationService.serviceEnabled();
print("Service status: $serviceStatus");
if (serviceStatus) {
_permission = await _locationService.requestPermission();
print("Permission: $_permission");
// If permission granted, get current location and subscribe to updates
if (_permission) {
LocationData location = await _locationService.getLocation();
final myLocationMarkerId = MarkerId("myLocationMarker");
myLocationMarker = Marker(
markerId: myLocationMarkerId,
position: LatLng(location.latitude, location.longitude),
icon: BitmapDescriptor.defaultMarker,
infoWindow: InfoWindow(
title: "My Location",
snippet: "Latitude: " +
location.latitude.toString() +
" Longitude: " +
location.longitude.toString()),
);
_locationSubscription = _locationService
.onLocationChanged()
.listen((LocationData result) async {
if (cameraUpdateToMyLocation) {
_currentCameraPosition = CameraPosition(
target: LatLng(result.latitude, result.longitude), zoom: 16);
// Safety check if mapController not null
if (mapController != null) {
mapController.animateCamera(
CameraUpdate.newCameraPosition(_currentCameraPosition));
}
}
if (mounted) {
setState(() {
_currentLocation = result;
myLocationMarker = myLocationMarker.copyWith(
positionParam: LatLng(
_currentLocation.latitude, _currentLocation.longitude),
infoWindowParam: InfoWindow(
title: "My Location",
snippet: "Latitude: " +
location.latitude.toString() +
" Longitude: " +
location.longitude.toString())
);
});
}
});
}
} else {
bool serviceStatusResult = await _locationService.requestService();
print("Service status activated after request: $serviceStatusResult");
if (serviceStatusResult) {
initPlatformState();
}
}
} on PlatformException catch (e) {
print(e);
if (e.code == 'PERMISSION_DENIED') {
error = e.message;
} else if (e.code == 'SERVICE_STATUS_ERROR') {
error = e.message;
}
}
}
I would like that this location update stops when the user moves the maps on the screen.
Unfortunately, the callback onCameraMove is triggered when the user move the map AND when the camera animation is launched.
Is it possible to trigger the inCameraMove callback, only when the user move the map ?
Thx !
EDIT It appears that onCameraMove is called in loop when I drag the map with my finger...
It's not possible to differentiate the onCameraMove callback as far as I know. What are you trying to accomplish here? Can you change the plugin to display the clusters onCameraIdle callback? Would this solve your problem?
unfortunately, the google maps flutter does not support this feature for now. you can handle it by wrapping a map in the listener and control a boolean that shows what kind of action makes the camera move. for example, I want to find out if the camera moves by click on the markers (calling on tap callback of marker moves the camera) or the user manually drags the map. every time the user touches the map I change the "dragsTheScreen" boolean to true, and in on tap function of markers I change it to false which shows the camera movement is because of markers. so you can do it for any feature you want. for example, you want to find out if the camera movement is because of calling your own Special function or the user dragging: listener changes the boolean("dragsTheScreen") to true, and that function setState it to false.
Listener(
onPointerDown: (PointerDownEvent event){
setState(() {
dragsTheScreen=false;
});
},
child: GoogleMap(
markers: markerItemsForShow.toSet(),
mapType: MapType.normal,
onMapCreated: onMapCreated,
onCameraMove: onCameraMove,
onCameraIdle: onCameraIdle,
initialCameraPosition:CameraPosition(tilt:25,target:LatLng(32.71,51.66), zoom: 5),
),
),
and in markers on tap callback when I am create them:
markerItemsForShow.add(Marker(
markerId:...,
position:...,
onTap: (){
setState(() {
dragsTheScreen=true;
});
}
));

Get Visible Markers in google_maps_flutter

Using Google Maps for Flutter I've placed some markers on different places on the map. I have a separate RaisedButton on my Flutter app which I need to only be visible when one or more of those markers are currently visible on the map.
How can this be achieved? I've found a somewhat similar solution for Google Maps API but I need this for google_maps_flutter on Flutter.
LatLngBounds has specific method known as contains() which works along with GoogleMapController's getVisibleRegion().
From the official docs:
contains(LatLng point) → bool
Returns whether this rectangle contains the given LatLng.
Usage:
Completer<GoogleMapController> _controller = Completer();
static final CameraPosition _positionCenter = CameraPosition(
target: LatLng(40.730610, -73.935242),
zoom: 3.5,
);
Future<LatLngBounds> _getVisibleRegion() async {
final GoogleMapController controller = await _controller.future;
final LatLngBounds bounds = await controller.getVisibleRegion();
return bounds;
}
#override
Widget build(BuildContext context) {
void checkMarkers() async {
LatLngBounds bounds = await _getVisibleRegion();
Set<Marker> markers = Set<Marker>.of(markers.values);
markers.forEach((marker) {
print('Position: ${ marker.position } - Contains: ${ bounds.contains(marker.position) }');
});
}
return GoogleMap(
mapType: MapType.normal,
markers: Set<Marker>.of(markers.values),
initialCameraPosition: _positionCenter,
onCameraIdle: () {
checkMarkers();
},
onMapCreated: (GoogleMapController controller) async {
_controller.complete(controller);
checkMarkers();
},
);
}
google_maps_flutter is a developer preview at version 0.0.3. Please hang in there a bit until more functionality is introduced.

Flutter get coordinates from google maps

I use the package google_maps_flutter to use Google maps in my app. My problem is how to set a listener, show when I press in the map to get the coordination of this place. I don't find anything in documentation.
The only thing which I find is with controllerMap, which I use to set marker listener, is that it has a method,
.addListener(listener)
Any idea?
I have solved the problem using the onMarkerTapped callback methods below:
Note: mapController below is an instance of the GoogleMap Controller
mapController.**onMarkerTapped**.add((marker){
String title= marker.options.infoWindowText.title;
String latitude= marker.options.position.latitude.toString();
String longitude= marker.options.position.longitude.toString();
});
google map plugin has a lot of errors:), I prefer using this plugin : flutter_map
full example :
import 'package:location/location.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong/latlong.dart';
class ContactPage extends StatefulWidget {
#override
ContactPageState createState() => new ContactPageState();
}
class ContactPageState extends State<ContactPage>
with TickerProviderStateMixin {
static LatLng myLocation = new LatLng(51.5, -0.09);
#override
void initState() {
super.initState();
setState(() {
new LatLng(51.5, -0.09);
});
}
#override
Widget build(BuildContext context) {
Size screenSize = MediaQuery.of(context).size;
double heigh = screenSize.height;
TextStyle whiteStyle = new TextStyle(fontSize: 20.0, color: Colors.white);
return new Directionality(
textDirection: TextDirection.rtl,
child: new Container(
padding: new EdgeInsets.only(bottom: 10.0, left: 1.0, right: 1.0),
color: Colors.white,
child: new FlutterMap(
options: new MapOptions(
center: myLocation,
zoom: 15.0,
maxZoom: 15.0,
minZoom: 3.0,
onTap: _handleTap),
layers: [
new TileLayerOptions(
urlTemplate:
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
subdomains: ['a', 'b', 'c']),
new MarkerLayerOptions(markers: markers)
],
)
)),
);
}
_handleTap(LatLng point) {
setState(() {
myLocation = point;
});
}
}
This functionality is currently not available in version 2.0 of the google flutter plugin, however there are two pull requests that have added this functionality.
1121
941
Pull request 1121 has example code on how to use the tap functionality.
With the current documentation, I only made the following change to the example of #lionelsanou and #Pradeep given above:
String latitude= marker.values.first.position.toString();
String longitude= marker.values.last.position.toString();
and it worked for me.

Meteor reactive maps don't work as should

I am using two brilliant packages named dburles:google-maps and mdg:geolocation. What I nee is to add a marker and change map's zoom automatically when I get user's geolocation data (after he allows it to share).
Inside Template.onCreated I have the following code:
Template.dealersMap.onCreated(function() {
Tracker.autorun(() => {
this.latLng = new ReactiveVar(Geolocation.latLng());
})
});
Then in onRendered I do the following:
Template.dealersMap.onRendered(function() {
navigator.geolocation.getCurrentPosition((position) => {
GoogleMaps.ready('exampleMap', (map) => {
let marker;
if(!this.latLng.get())
console.log('Didn\'t get the location..');
if(!marker) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(
this.latLng.get().lat,
this.latLng.get().lng
),
map: map.instance
});
} else {
marker.setPosition(this.latLng.get());
}
map.instance.setCenter(marker.getPosition());
map.instance.setZoom(11);
}, () => {
console.log('deny');
});
})
});
As result after user allows me to get his geodata nothing happens. But if user changes at least one step map zoom — everything works.
The question is — how to make this code work without letting user change map zoom?
I just removed navigator.geolocation.getCurrentPosition and now everything works fine. Here is the successful code:
Template.dealersMap.onCreated(function() {
this.latLng = new ReactiveVar();
Tracker.autorun(() => {
this.latLng.set(Geolocation.latLng());
})
});
Template.dealersMap.onRendered(function() {
this.autorun(() => {
GoogleMaps.ready('exampleMap', (map) => {
console.log('map is ready');
let marker;
if(!this.latLng.get()) {
console.log('Didn\'t get the location..');
} else {
if(!marker) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(
this.latLng.get()
.lat,
this.latLng.get()
.lng
),
map: map.instance
});
} else {
marker.setPosition(this.latLng.get());
}
}
map.instance.setCenter(marker.getPosition());
map.instance.setZoom(11);
})
})
});
You can use Tracker to rerun the once the dta is changed like, once uses share his/her location, the marker is triggered. Here is the example code:
Template.dealersMap.onRendered(function() {
var self=this;
navigator.geolocation.getCurrentPosition((position) => {
GoogleMaps.ready('exampleMap', (map) => {
self.autorun(function() { //tracker function
let marker;
if(!this.latLng.get())
console.log('Didn\'t get the location..');
if(!marker) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(
this.latLng.get().lat,
this.latLng.get().lng
),
map: map.instance
});
} else {
marker.setPosition(this.latLng.get());
}
map.instance.setCenter(marker.getPosition());
map.instance.setZoom(11);
}, () => {
console.log('deny');
}
});
})
});