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!
Related
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.
Good day,
I am currently learning flutter under the Udemy course and at the moment is implementing maps in the app. The current lecture is using Google Maps to add markers on it when user taps on the screen, however I use a different API (Mapbox) and try to implement the same output.
Currently here is the issue I have encountered when I try to compile my code:enter image description here
My code can be found here:
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
import 'package:native_func_app/models/place.dart';
import '../models/place.dart';
class MapScreen extends StatefulWidget {
//const MapScreen({ Key? key }) : super(key: key);
final PlaceLocation initialLocation;
final bool isSelecting;
MapScreen({
this.initialLocation =
const PlaceLocation(latitude: 37.421, longitude: -122.084),
this.isSelecting = false,
});
#override
_MapScreenState createState() => _MapScreenState();
}
class _MapScreenState extends State<MapScreen> {
LatLng _pickedLocation;
void _selectLocation(LatLng position) {
setState(() {
_pickedLocation = position;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Your Map'),
),
body: FlutterMap(
options: MapOptions(
center: LatLng(widget.initialLocation.latitude,
widget.initialLocation.longitude),
zoom: 16.0,
//onTap: widget.isSelecting ? _selectLocation: null,
onTap: widget.isSelecting ? _selectLocation : () {},
),
layers: [
TileLayerOptions(
urlTemplate:
"https://api.mapbox.com/styles/v1/dhe/ckwd8qofr09gd14oq5d8djor9/tiles/256/{z}/{x}/{y}#2x?access_token=pk.eyJ1IjoiZGhlIiwiYSI6ImNrdnFybGw4ZzI1cWgycm91MXBpcW9oN3kifQ.fzK2_BFZrGU_vMpwTuU2Kg",
/*subdomains: ['a', 'b', 'c'],
attributionBuilder: (_) {
return Text("© OpenStreetMap contributors");
},*/
additionalOptions: {
'accessToken':
'pk.eyJ1IjoiZGhlIiwiYSI6ImNrdnFybGw4ZzI1cWgycm91MXBpcW9oN3kifQ.fzK2_BFZrGU_vMpwTuU2Kg',
'id': 'mapbox.mapbox-streets-v8',
}),
MarkerLayerOptions(
markers: _pickedLocation == null
? []
: [
Marker(
point: _pickedLocation,
builder: (ctx) => Container(
child: FlutterLogo(),
),
),
],
),
],
),
);
}
}
Right now, someone ask me to replace the null code with (){} to see if the error goes away and it does. However a new issue occurs when I recompile as seen here: 2nd issue crash at compile time
Can anyone help me identify the issue?
If you need to access my project ill link the Github Project I am using to view the source codes:
https://github.com/DheDeveloperUsv/native_func_app
Any help or insight to resolve this issue is very much welcome.
Add a parameter tapPosition to your _selectLocation
void _selectLocation(TapPosition tapPosition, LatLng position) {
setState(() {
_pickedLocation = position;
});
}
onTap needs a function with 2 Parameters and no return value (void).
So this won't be working:
widget.isSelecting ? _selectLocation : () {}
_selecteLocation is a function this 1 parameter
and (){} has no parameters. change (){} to (TapPosition tapPosition, LatLng position){}
complete code:
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
import 'package:native_func_app/models/place.dart';
import '../models/place.dart';
class MapScreen extends StatefulWidget {
//const MapScreen({ Key? key }) : super(key: key);
final PlaceLocation initialLocation;
final bool isSelecting;
MapScreen({
this.initialLocation =
const PlaceLocation(latitude: 37.421, longitude: -122.084),
this.isSelecting = false,
});
#override
_MapScreenState createState() => _MapScreenState();
}
class _MapScreenState extends State<MapScreen> {
LatLng _pickedLocation;
void _selectLocation(TapPosition tapPosition, LatLng position) {
setState(() {
_pickedLocation = position;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Your Map'),
),
body: FlutterMap(
options: MapOptions(
center: LatLng(widget.initialLocation.latitude,
widget.initialLocation.longitude),
zoom: 16.0,
//onTap: widget.isSelecting ? _selectLocation: null,
onTap: widget.isSelecting ? _selectLocation : (TapPosition tapPosition, LatLng position) {},
),
layers: [
TileLayerOptions(
urlTemplate:
"https://api.mapbox.com/styles/v1/dhe/ckwd8qofr09gd14oq5d8djor9/tiles/256/{z}/{x}/{y}#2x?access_token=pk.eyJ1IjoiZGhlIiwiYSI6ImNrdnFybGw4ZzI1cWgycm91MXBpcW9oN3kifQ.fzK2_BFZrGU_vMpwTuU2Kg",
/*subdomains: ['a', 'b', 'c'],
attributionBuilder: (_) {
return Text("© OpenStreetMap contributors");
},*/
additionalOptions: {
'accessToken':
'pk.eyJ1IjoiZGhlIiwiYSI6ImNrdnFybGw4ZzI1cWgycm91MXBpcW9oN3kifQ.fzK2_BFZrGU_vMpwTuU2Kg',
'id': 'mapbox.mapbox-streets-v8',
}),
MarkerLayerOptions(
markers: _pickedLocation == null
? []
: [
Marker(
point: _pickedLocation,
builder: (ctx) => Container(
child: FlutterLogo(),
),
),
],
),
],
),
);
}
}
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.
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
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);
}),
)