How to get marker latitude and longitude on flutter map? - flutter

I'm using google_maps_flutter package to display the map and I placed a marker so the user can select a location (not the user location any location on the map).
like this
Now the user can drag the marker where he want ,
my question is
Can I get latitude and longitude for marker after user drag it?
here is my full code
class _BodyState extends State<Body> {
MapType mapType = MapType.normal;
Completer<GoogleMapController> _controller = Completer();
LocationServices _locationServices;
LocationData _locationData;
CameraPosition _cameraPosition;
Set<Marker> allMapMarkers;
Marker userPicker;
#override
Widget build(BuildContext context) {
_locationServices=Provider.of<LocationServices>(context);
return FutureBuilder(
future: _locationServices.getLocation().then((LocationData value) => _locationData=value),
builder:(context,snapshot){
if(_locationData==null){
return Center(child: CircularProgressIndicator());
}else{
_cameraPosition=CameraPosition(target:LatLng(_locationData.latitude,_locationData.longitude),zoom: 19);
setupMarkers(); // this set the Lat and Long for marker
return SafeArea(
child: Stack(
children: [
GoogleMap(
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
},
initialCameraPosition: _cameraPosition,
mapType: mapType,
compassEnabled: false,
zoomControlsEnabled: false,
markers: allMapMarkers,
),

You can use the Marker from google_maps_flutter plugin to fetch marker coordinates. It has an onDrag property that returns a LatLng object that contains coordinates. Use the onDragEnd property to fetch the coordinates on where the marker has been placed.
Marker(
onTap: () {
debugPrint('Tapped');
},
draggable: true,
markerId: MarkerId('Marker'),
onDragEnd: ((LatLng newPosition) {
debugPrint(newPosition.latitude);
debugPrint(newPosition.longitude);
}),
)

Related

is there a marker clustering library that works with Flutter bloc and Google Maps?

I ran into a bit of a wall when i tried to implement marker clustering in a Google Maps based app that i'm developing for work.
I figured i could use circles to represent clusters and swap markers for circles at a certain zoom threshold but that didn't work out, so now I'm using a clustering library.
The main issue is that said library doesn't take into account if the app uses a state management library, so here i am with an empty map once again.
I render my map like this:
class MapView extends StatelessWidget {
final LatLng initialLocation;
final Set<Marker> markers;
final CustomInfoWindowController infoWindowController;
final GoogleMapController? mapController;
final ClusterManager manager;
Completer<GoogleMapController> newMapController = Completer();
MapView(
{Key? key,
required this.initialLocation,
required this.markers,
required this.manager,
required this.infoWindowController,
this.mapController})
: super(key: key);
#override
Widget build(BuildContext context) {
final CameraPosition initialCameraPosition =
CameraPosition(target: initialLocation);
final renderSize = MediaQuery.of(context).size;
return SizedBox(
width: renderSize.width,
height: renderSize.height,
child: GoogleMap(
onTap: (position) {
infoWindowController.hideInfoWindow!();
if (context.read<MapBloc>().state.creatingLocation == true) {
context.read<MapBloc>().add(TurnCreationModeOff());
}
},
onCameraMove: (position) {
infoWindowController.onCameraMove!();
manager.onCameraMove(position);
},
onCameraIdle: () {
context.read<MapBloc>().add(HoldZoomLevel());
manager.updateMap();
context.read<MapBloc>().printMapID();
},
onLongPress: (LatLng location) {
context
.read<LocationCreationBloc>()
.add(LocationAcquired(location: location));
final Marker newMarker = Marker(
draggable: true,
markerId: const MarkerId('new'),
position: location,
icon: BitmapDescriptor.defaultMarkerWithHue(
BitmapDescriptor.hueViolet),
infoWindow: InfoWindow(
title: 'Pulsame para crear una nueva ubicacion',
snippet:
'Toca cualquier lado del mapa y reajusta el zoom para destruirme',
onTap: () {
Navigator.of(context).pushAndRemoveUntil(
CreationScreen.route(), (route) => false);
},
));
context.read<MapBloc>().add(RenderNewMarker(marker: newMarker));
},
initialCameraPosition: initialCameraPosition,
compassEnabled: true,
myLocationEnabled: true,
markers: markers,
zoomControlsEnabled: false,
myLocationButtonEnabled: true,
mapToolbarEnabled: false,
onMapCreated: (GoogleMapController controller) {
context.read<MapBloc>().add(MapInitialized(
controller: controller,
windowController: infoWindowController,
clusterManager: manager,
location:
context.read<LocationBloc>().state.lastKnownLocation));
newMapController.complete(controller);
manager.setMapId(controller.mapId);
infoWindowController.googleMapController = controller;
},
)
);
}
}
some stuff is heavily context dependant and i'd be happy to elaborate and provide more code samples if anyone needs them or has run into a similar issue.
i tried recoupling my business logic with my presentation layer, that being initializing a List of clusterable items and passing it to the Cluster Manager constructor but it crashed at runtime.

Google_Maps_Flutter 'onTap' function not working

I use the "google_maps_flutter 2.1.8" package for a new project, but I can't get the 'onTap' function working. Not even to print something.
After I spent the whole day trying to find the problem, I guess I need some help now.
Do I have to activate the function somehow.
I am grateful for any advice!
My current code looks like this:
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:google_maps_controller/google_maps_controller.dart';
import 'package:test/SecondScreen.dart';
class Home extends StatefulWidget{
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
late GoogleMapController mapController; //controller for Google map
final Set<Marker> markers = new Set(); //markers for google map
static const LatLng showLocation = const LatLng(51.2333, 6.783333); //initial Location
late BuildContext _myContext; //Try OnTap Function Delete if not working
#override
Widget build(BuildContext context) {
_myContext = context; //Try OnTap Function Delete if not working
return Scaffold(
appBar: AppBar(
title: Text("Multiple Markers in Google Map"),
backgroundColor: Color.fromARGB(200, 13, 127, 229)
),
body: GoogleMap( //Map widget from google_maps_flutter package
zoomGesturesEnabled: true, //enable Zoom in, out on map
initialCameraPosition: CameraPosition( //inital position in map
target: showLocation, //initial position
zoom: 15.0, //initial zoom level
),
markers: getmarkers(), //markers to show on map
mapType: MapType.normal, //map type
onMapCreated: (controller) { //method called when map is created
setState(() {
mapController = controller;
});
},
),
);
}
//Markers Only
Set<Marker> getmarkers() { //markers to place on map
setState(() {
markers.add(Marker( //add first marker
markerId: MarkerId(showLocation.toString()),
position: showLocation, //position of marker
infoWindow: InfoWindow( //popup info
title: 'Marker Title First ',
snippet: 'My Custom Subtitle',
onTap: () {
Navigator.push(
_myContext,
MaterialPageRoute(builder: (context) => SecondScreen())
);
},
),
icon: BitmapDescriptor.defaultMarker, //Icon for Marker
));
markers.add(Marker( //add second marker
markerId: MarkerId(showLocation.toString()),
position: LatLng(51.23, 6.78), //position of marker
infoWindow: InfoWindow( //popup info
title: 'Marker Title Second ',
snippet: 'My Custom Subtitle',
onTap: (){
print('tap');
},
),
icon: BitmapDescriptor.defaultMarker, //Icon for Marker
));
markers.add(Marker( //add third marker
markerId: MarkerId(showLocation.toString()),
position: LatLng(51.22, 6.776), //position of marker
infoWindow: InfoWindow( //popup info
title: 'Marker Title Third ',
snippet: 'My Custom Subtitle',
),
icon: BitmapDescriptor.defaultMarker, //Icon for Marker
));
//add more markers here
});
return markers;
}
}
We found the problem, I gave multiple markers the same MarkerId. After I changed it, it worked fine. Sorry guys, case closed!

How to add markers to a flutter google map after the map has been created and change the camera position?

I am new to Flutter and I have created a google map using the flutter_google_maps package.
I have the following code in my parent widget,
SizedBox(
child: _showFindHouseModal
? FutureBuilder<Address?>(
future: _locationDataFuture,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Map(
initialLatitude: _userLocation.latitude!.toDouble(),
initialLongitude: _userLocation.longitude!.toDouble(),
markers: const [],
);
}
},
)
: FutureBuilder<Address?>(
future: _showFindHouseModal,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Map( // <---------------------------------------- This one is the problem
initialLongitude: _userLocation.latitude!.toDouble(),
initialLatitude: _userLocation.latitude!.toDouble(),
markers: [
Marker(
markerId: MarkerId('${_housesList.first.id}'),
position: LatLng(_housesList.first.houseLatitude, _housesList.first.houseLongitude),
),
],
);
}
}),
),
In the above code, you can see that I am using a ternary operator. if _showFindHouseModal is true a Map widget is built. If it is not true, the same Map widget will be built but with additional markers. The problem is, those additional markers I am forwarding are not rendered on the screen.
However, I think I figured out the problem. It is in the child widget. (It is that I can not find a solution to the problem)
Let me show the code for the child widget.
class Map extends StatefulWidget {
final List<Marker> markers;
final double initialLatitude;
final double initialLongitude;
const Map({
Key? key,
required this.initialLatitude,
required this.initialLongitude,
required this.markers, // Todo: Make the default to an empty value
}) : super(key: key);
#override
State<Map> createState() => MapState();
}
class MapState extends State<Map> {
late final CameraPosition _initialCameraPosition;
late final Set<Marker> _markers = {};
final Completer<GoogleMapController> _controller = Completer();
#override
void initState() {
super.initState();
_initialCameraPosition = CameraPosition(
target: LatLng(widget.initialLatitude, widget.initialLongitude),
zoom: 12,
);
}
#override
Widget build(BuildContext context) {
return GoogleMap(
mapType: MapType.normal,
initialCameraPosition: _initialCameraPosition,
markers: _markers,
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
setState(
() {
_markers.addAll(widget.markers); <--------- This is the problem I think
_markers.add(
Marker(
markerId: const MarkerId('user-marker'),
position: LatLng(widget.initialLatitude, widget.initialLongitude),
),
);
},
);
},
);
}
}
As I have pointed out in the code, I think the problem is, inside the child widget, those markers are added under the onMapCreated property. Since the map is already created in the first FutureBuilder, those markers are not added to the map for some reason. I can not figure out how to add new markers from the second FutureBuilder. The markers I am adding are not passed through.
Can someone please help. I have been trying to find a way for 6 or so hours and could not make it.
try this, change the line you assign the markers
markers: _markers
along this line
markers: Set<Marker>.of(_markers.values),
this may help you
bool mapToggle = false;
Position currentLocation;
GoogleMapController mapController;
GoogleMap googleMap;
var ads = [];
Map<MarkerId, Marker> markers = <MarkerId, Marker>{};
MarkerId selectedMarker;
LatLng markerPosition;
bool clientToggle = false;
#override
void initState() {
super.initState();
// GeolocationStatus geolocationStatus = await Geolocator.checkGeolocationPermissionStatus();
// Geolocator.checkPermission();
// Geolocator.getServiceStatusStream();
Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high)
.then((currloc) {
setState(() {
currentLocation = currloc;
mapToggle = true;
populateClient();
});
});
}
#override
void dispose() {
super.dispose();
}
populateClient() {
kfirestore.collection('marks').get().then((value) {
if (value.docs.isNotEmpty) {
setState(() {
clientToggle = true;
});
for (int i = 0; i < value.docs.length; i++) {
ads.add(value.docs[i].data());
initMarker(value.docs[i].data(), value.docs[i].id);
var _distanceBetweenLastTwoLocations = Geolocator.distanceBetween(
value.docs[i].data()['location'].latitude,
value.docs[i].data()['location'].longitude,
currentLocation.latitude,
currentLocation.longitude,
);
print("bairshiluud:" + _distanceBetweenLastTwoLocations.toString());
if (_distanceBetweenLastTwoLocations < 100) {
SuccessDialog(
title: "Таны байршилтай ойр сурталчилгаа",
titleColor: Colors.green,
description: value.docs[i].data()['adName'],
);
} else {
SuccessDialog(
title: "Таны байршилтай ойр сурталчилгаа",
titleColor: Colors.green,
description: "Таны байршилд ойр сурталчилгаа олдсонгүй.",
);
}
}
}
});
}
void initMarker(specify, specifyId) async {
var markerIdVal = specifyId;
final MarkerId markerId = MarkerId(markerIdVal);
final Marker marker = Marker(
markerId: markerId,
position: LatLng(
specify['location'].latitude,
specify['location'].longitude,
),
infoWindow: InfoWindow(title: specify['adName'], snippet: "Сурталчилгаа"),
icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueRose),
);
setState(() {
markers[markerId] = marker;
});
}
Container(
height: MediaQuery.of(context).size.height - 80,
width: double.infinity,
child: mapToggle
? GoogleMap(
mapType: MapType.hybrid,
compassEnabled: true,
onMapCreated: onMapCreated,
buildingsEnabled: true,
myLocationButtonEnabled: true,
myLocationEnabled: true,
rotateGesturesEnabled: true,
zoomControlsEnabled: true,
zoomGesturesEnabled: true,
indoorViewEnabled: true,
mapToolbarEnabled: true,
tiltGesturesEnabled: true,
scrollGesturesEnabled: true,
initialCameraPosition: CameraPosition(
target: LatLng(currentLocation.latitude,
currentLocation.longitude),
zoom: 15,
),
// circles: circles,
markers: Set<Marker>.of(markers.values),
)
: Center(
child: Text("Loading"),
),
),
1- It is not high possibile but maybe you can change markers: const [] line to just [] without cons keyword.
2- This one more possible than first one, try to cover with one of them future builder, with different widget like SizedBox or give one of them unique key. (but i suggest first approach like; condition? FutureBuilder:SizedBox(child: FutureBuilder)) because, your problem can be releated widget tree rendering. İf this solve your problem I can add a youtube link about that and you can understand the meaning what I am trying to point out.
3- for camera position, after on camera create function call, with help initialed googleMapsController, you can change camera position, camera zoom and some other stuffs with googleMapsController.animateCamera() function,
example; googleMapsController.animateCamera(CameraUpdate.newLatLng(latLng)) will change the google maps view to your new lat long point. So I suggest, dont't use future builder for this, just animate your camera after initialing and you can cover your map widget with IgnorePointer before getting locations, in this way you can ensure the animation can't block from user interaction.

in Flutter, how to resize a googleMap marker

I display in my application a google map and a marker on a predefined position. I also changed the icon of the marker but it is too large and above all does not adapt to the size of the screen and its definition.
I would therefore like to adapt the dimensions of cd nouveau marker to the size of my screen. First of all, how to change its size?
My code is the following:
class _MyAppState extends State<MyApp>{
late GoogleMapController mapController;
....
late BitmapDescriptor iconMareaEstLa;
final List<Marker> _listMk =[];
....
void _onMapCreated(GoogleMapController controller){
mapController = controller;
setState(() {
_listMk.add(
Marker(
markerId: const MarkerId('MKIDPOSMAREA'),
draggable: false,
icon: iconMareaEstLa,
position: (LatLng(posMareaLat,posMareaLng)),
)
);
});
}
....
#override
void initState(){
super.initState();
BitmapDescriptor
.fromAssetImage(
const ImageConfiguration(size:Size(50,50)),
'images/MareaBlancFondBlanc.png')
.then((value) => iconMareaEstLa = value);
}
...
Widget build(BuildContext context) {
MediaQueryData queryData;
queryData = MediaQuery.of(context);
screenW =queryData.size.width;
screenH =queryData.size.height;
return Scaffold(
body: Stack(
children: [
GoogleMap(
markers: Set.of(_listMk),
onMapCreated: _onMapCreated,
mapType: _currentMapType,
myLocationButtonEnabled: false,
zoomControlsEnabled: false,
initialCameraPosition: CameraPosition(
target: _center,
zoom: 14.0
),
),
....
Can someone tell me where and how to specify the dimensions of my new marker.
Merci
YC

Google Maps Current User Location - Flutter

I am trying to get the user's current location from Google Maps but I am getting an exception in return which I can't seem to understand why it's happening.
The app is simple - get the user's current location, and then zoom the camera onto that location. That's it.
I am going to attach my code and the exception message. The strange thing is that I am getting my LatLng correctly as you can see in the exception message, so why is the camera not pointing to that location?
class Map extends StatefulWidget {
#override
_MapState createState() => _MapState();
}
class _MapState extends State<Map> {
LatLng currentLatLng;
Completer<GoogleMapController> _controller = Completer();
#override
void initState(){
super.initState();
Geolocator.getCurrentPosition().then((currLocation){
setState((){
currentLatLng = new LatLng(currLocation.latitude, currLocation.longitude);
});
});
}
#override
Widget build(BuildContext context) {
print("Current Location --------> " + currentLatLng.latitude.toString() + " " + currentLatLng.longitude.toString());
return MaterialApp(
home: new Scaffold(
body: GoogleMap(
mapType: MapType.normal,
initialCameraPosition: CameraPosition(target: currentLatLng),
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
},
),
),
);
}
}
note - I am using 'geolocator' and 'google_maps_flutter' from pub.dev - all latest versions.
This is async programming. currentLatLng is null until getCurrentPosition calls it's callback, so you can't just do this:
initialCameraPosition: CameraPosition(target: currentLatLng)
because, as you error shows, currentLatLng is null.
Your two options are:
Set the map to a default position that you define and then update the position using the mapcontroller when getCurrentPosition completes.
Show a loader while currentLatLng is null, and when it's no longer null, show your map.
Here's an example for 2
return MaterialApp(
home: new Scaffold(
body: currentLatLng == null ? Center(child:CircularProgressIndicator()) : GoogleMap(
mapType: MapType.normal,
initialCameraPosition: CameraPosition(target: currentLatLng),
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
},
),
),
);