How can I get tapped location in flutter_map? - flutter

I'm implementing a map in my code. So far this is what I have:
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_map_tappable_polyline/flutter_map_tappable_polyline.dart';
import 'package:latlong/latlong.dart';
import 'package:geolocator/geolocator.dart';
class MapPicker extends StatefulWidget {
MapPicker({Key key}) : super(key: key);
#override
_MapPicker createState() {
return _MapPicker();
}
}
class _MapPicker extends State<MapPicker> {
Position _position;
void getLocation() async {
var position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
print(position);
setState(() {
_position = position;
});
}
#override
Widget build(BuildContext context) {
if(_position == null)
getLocation();
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text('Escoger Localización'),
),
body: _position != null ? FlutterMap(
options: MapOptions(
center: LatLng(18.0119098, -66.6159138), //Change to _position
zoom: 15.0
),
layers: [
TileLayerOptions(
urlTemplate:
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
subdomains: ['a', 'b', 'c']),
MarkerLayerOptions(
markers: [],
),
TappablePolylineLayerOptions(
onTap: (TaggedPolyline polyline) => print(polyline.tag)
)
],
)
:
CircularProgressIndicator(),
);
}
}
I'm using a set LatLon for now for test purposes but the idea is using _position to use the current position when opening the map. But, my problem is the following: I want to be able to tap any place in the map and get the coordinates for the place I tapped. Is this possible?

options: new MapOptions(
onTap: (tapPosition, point) => {
print(point.toString()),
},
center: LatLng(0, 0),
zoom: 1,
maxZoom: 19,
),

This is possible through the onTap() callback I think available in MapOptions(). It returns the position tapped.

Related

The argument type 'LatLng' can't be assigned to the parameter type 'LatLng?'

when am using flutter_map in MapOptions-> Center when entering the lat and lng am getting an error The argument type 'LatLng' can't be assigned to the parameter type 'LatLng?'.
class MapsView extends HookConsumerWidget {
MapsView({Key? key}) : super(key: key);
final MapController _mapController=MapController();
#override
Widget build(BuildContext context, WidgetRef ref) {
return FlutterMap(
options: MapOptions(
center: LatLng(51.509364, -0.128928),
zoom: 9.2,
),
layers: [
TileLayerOptions(
urlTemplate: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
userAgentPackageName: 'com.example.app',
),
],
nonRotatedChildren: [
AttributionWidget.defaultWidget(
source: 'OpenStreetMap contributors',
onSourceTapped: null,
),
],
);
}
}
import 'package:latlong2/latlong.dart';
import 'package:flutter_map/flutter_map.dart';
class MapsView extends HookConsumerWidget {
MapsView({Key? key}) : super(key: key);
final MapController _mapController=MapController();
#override
Widget build(BuildContext context, WidgetRef ref) {
return FlutterMap(
options: MapOptions(
center: LatLng(51.509364, -0.128928),
zoom: 9.2,
),
layers: [
TileLayerOptions(
urlTemplate: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
userAgentPackageName: 'com.example.app',
),
],
nonRotatedChildren: [
AttributionWidget.defaultWidget(
source: 'OpenStreetMap contributors',
onSourceTapped: null,
),
],
);
}
}
import 'package:latlong2/latlong.dart
that is not exported in the package so you have to import this manually to be able to assign values in it
I think you need are not using latLng2
dependencies:
latlong2: ^0.8.0
import 'package:latlong2/latlong.dart' as latLng;
FlutterMap(
options: MapOptions(
center: latLng.LatLng(51.509364, -0.128928),
zoom: 9.2,
),
If you already using latlong: ^0.6.1 or higher
then you need to change your import
from:
import "package:latlong/latlong.dart" as latLng;
to:
import 'package:latlong2/latlong.dart' as latLng;
and it will be fine.

how i can use google map to get current location or choose location?

i start with this code but all what i get white screen
how i can use google map to get current location or choose location.I am using GoogleMap package in flutter to get the required current location.
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget { #override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Google Maps Demo', home: MapSample(), ); } }
class MapSample extends StatefulWidget { #override
State createState() => MapSampleState();
}
class MapSampleState extends State {
Completer _controller = Completer();
static final CameraPosition _kGooglePlex = CameraPosition( target:
LatLng(37.42796133580664, -122.085749655962), zoom: 14.4746, );
static final CameraPosition _kLake = CameraPosition( bearing:
192.8334901395799, target: LatLng(37.43296265331129,
-122.08832357078792), tilt: 59.440717697143555, zoom:
19.151926040649414);
#override Widget build(BuildContext context) { return new Scaffold(
body: GoogleMap(
mapType: MapType.hybrid, initialCameraPosition: _kGooglePlex,
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
},
),
floatingActionButton:
FloatingActionButton.extended(
onPressed: _goToTheLake,
label:
Text('To the lake!'),
icon: Icon(Icons.directions_boat), ),
);
}
Future _goToTheLake() async {
final GoogleMapController controller = await _controller.future;
controller.animateCamera(CameraUpdate.newCameraPosition(_kLake));
}
}
If you're using Url properly(no spelling/parameter mistakes) with API key and there's no error from the server which happens a lot due to restrictions. Then there are other steps you need to, ask Location permission on app loading using https://pub.dev/packages/permission_handler package like this.
Code can be something like this.
Create an app_persmission_provider file.
class AppPermissionProvider with ChangeNotifier {
PermissionStatus _locationStatus = PermissionStatus.denied;
LatLng? _locationCenter;
final location_package.Location _location =
location_package.Location();
location_package.LocationData? _locationData;
// Getter
get locationStatus => _locationStatus;
get locationCenter => _locationCenter;
get location => _location;
void getLocationStatus() async {
final status = await Permission.location.request();
_locationStatus = status;
notifyListeners();
print(_locationStatus);
}
void getLocation() async {
_locationData = await _location.getLocation();
_locationCenter = LatLng(
_locationData!.latitude as double, _locationData!.longitude as double);
notifyListeners();
}
}
Then declare the provider on the root maybe, and In my case, I'm initializing some functions onInit. By doing so, android will ask for permission for location when your page loads.
#override
void initState() {
super.initState();
appPermission = Provider.of<AppPermissionProvider>(context, listen: false);
appPermission.getLocationStatus();
appPermission.getLocation();
}
And then using consumer.
SafeArea(
child: Consumer<AppPermissionProvider>(
builder: (context, appPermissionProvider, _) => appPermission
.locationCenter ==
null
? const Center(child: CircularProgressIndicator())
:
GoogleMap( myLocationButtonEnabled:
appPermissionProvider.locationStatus ==
PermissionStatus.granted
? true
: false,
myLocationEnabled: true,
initialCameraPosition: CameraPosition(
target: appPermission.locationCenter,
zoom: 14,
),
onMapCreated: onMapCreated,
mapType: MapType.normal,
compassEnabled: true,
),
),
)
Here, I am checking if permission is granted, also I am only enabling myLocationButton if location permission is granted.
You can use google_maps_flutter package ,
A short example how you can use it.
For more clearity you can visit
Here or you can use geolocator.
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
LatLng _initialcameraposition = LatLng(20.5937, 78.9629);
GoogleMapController _controller;
Location _location = Location();
void _onMapCreated(GoogleMapController _cntlr)
{
_controller = _cntlr;
_location.onLocationChanged.listen((l) {
_controller.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(target: LatLng(l.latitude, l.longitude),zoom: 15),
),
);
});
}

Argument Type Mismatch -using Mapbox API

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(),
),
),
],
),
],
),
);
}
}

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.

cant set my location on flutter google maps

I am newbie in flutter, I am trying to set my location as the center point of the map that the app draw on the screen
I am using statefulwidget as the root of my app and add this code :
class MyMap extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return MyMapState();
}
}
class MyMapState extends State<MyMap> {
GoogleMapController googleMapController;
LocationData currentLocation;
LocationData distinationLocation;
Location location;
#override
void initState() {
location = Location();
setInitSourceAndDestination();
super.initState();
}
setInitSourceAndDestination() async {
currentLocation = await location.getLocation();
}
#override
Widget build(BuildContext context) {
CameraPosition initialCameraPosition = CameraPosition(
target: LatLng(currentLocation.latitude, currentLocation.longitude),);
return GoogleMap(
initialCameraPosition: initialCameraPosition,
onMapCreated: (GoogleMapController controller) => googleMapController = controller,
mapType: MapType.normal,
tiltGesturesEnabled: false,
compassEnabled: true,
myLocationEnabled: true,
);
}
}
But there are a problem I can not solve:
the map is drawn in the screen before currentLocation is set
I tried setState and the problem has not been solved.
How can I make the app draw the map after setInitSourceAndDestination method finish excuting?
What make me confused is that the code at this form the build method will be excuted before setInitSourceAndDestination method finished, but if I add setState and change the currentLocation value inside it to rebuild the screen I noticed that setState executed before build function but it still dont show my location
Add a condition to check the state. If the state is null, then draw a loading indicator. If not null, draw the maps
it can be look like this :
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:location/location.dart';
class MapScreen extends StatefulWidget {
#override
_MapScreenState createState() => _MapScreenState();
}
class _MapScreenState extends State<MapScreen> {
double lat;
double long;
LatLng _pickedLoc;
Future _getLocation() async {
LocationData location = await Location().getLocation();
setState(() {
lat = location.latitude;
long = location.longitude;
});
}
_selectLocation(LatLng location) {
_pickedLoc = location;
}
#override
void initState() {
super.initState();
_getLocation();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: lat == null || long == null
? Center(
child: CircularProgressIndicator(),
)
: GoogleMap(
initialCameraPosition: CameraPosition(
zoom: 16,
target: LatLng(lat, long),
),
onTap: _selectLocation,
onCameraMove: (object) => {debugPrint(object.target.toString())},
markers: {
Marker(
markerId: MarkerId("m1"),
position: _pickedLoc,
)
},
),
);
}
}