I'm just starting with Flutter and very new to State/Stream/BloC concepts. I'm trying to update a FlutterMap center based on the coordinates from a Geolocator()'s Position stream. At the moment I'm just calling setState() updating a variable with the new value, but next I'll be trying using the Bloc pattern instead..
Now, as well as I set the center on the coordinates of the Position coming from the stream I also set a Marker on the same coordinates. I was expecting to see a Steady marker in the center of the screen and a moving map underneath but is the opposite.. the Map is steady and the Icon is moving.. Can you see where I got it wrong?
Also, for the stream: property of the StreamBuilder how would I get to pass the stream from Geolocator() as an event?
Many thanks for your time and help.
This is the Stream:
StreamSubscription positionStream = _geolocator
.getPositionStream(locationOptions)
.listen((Position position) {
setState(() {
_position = position;
});
print(
_position.latitude.toString() + ',' + _position.longitude.toString()); // ok
});
And this is the Map and the Marker:
Container(
height: 670,
width: 370,
child: FlutterMap(
options: MapOptions(
center: LatLng(_position.latitude, _position.longitude),
minZoom: 16.0,
maxZoom: 19.0,
),
layers: [
TileLayerOptions(
// urlTemplate:
// 'https://api.openrouteservice.org/mapsurfer/{z}/{x}/{y}.png?api_key=omitted',
urlTemplate:
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
subdomains: ['a', 'b', 'c'],
keepBuffer: 20),
new MarkerLayerOptions(
markers: [
new Marker(
point: new LatLng(
_position.latitude, _position.longitude),
height: 200,
width: 200,
builder: (context) => IconButton(
icon: Icon(Icons.location_on),
color: Colors.red,
iconSize: 60,
onPressed: () {
print('icon tapped');
},
)),
],
),
],
),
),
Found the problem. I didn't assign any MapController().
So I created one and assign it to the FlutterMap. Inside the setState() I added _controller.move(LatLng(_position.latitude, _position.longitude), 16.0); and now the behaviour is the expected one. Steady Icon in the center of the screen and a moving map underneath.
Hope this will help others.
But still I will try to achieve the same with a BLoC pattern.
Cheers
Related
I have a Flutter app which requires location services. I have already implemented getting a users current location, permissions, etc...
My app has to position a marker on a map when first open based on the current location of the user. (This is what I need help with)
The user can later touch the map at any other point to place the marker at that point. (This I have already done)
I have successfully created a function which can retrieve the current location of a user like this, (Do note that that function is async)
Future<LatLng> get currentLocation async {
Position pos = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
);
return LatLng(pos.latitude, pos.longitude);
}
I currently have LatLng markerPoint = LatLng(12.9716, 77.5946); as my initial marker point inside of my HomePage like this,
class _HomePageState extends State<HomePage> {
// Initial marker location
LatLng markerPoint = LatLng(12.9716, 77.5946);
...
But I want the current location returned by my function to replace the values given here. I am unable to do something like LatLng markerPoint = await _locationService.currentLocation; because I cannot make that part of the class async.
So, that's basically my problem. I want to initialise my variable through an asynchronous function, but I haven't found a way to do that since the area I am in, does not allow for async functions.
Help will be appreciated.
PS:
My remaining build function which sets the marker point whenever touched is over here for your reference.
#override
Widget build(BuildContext context) {
return Stack(
children: [
FlutterMap(
options: MapOptions(
onTap: (tapPosition, point) async {
setState(() {
markerPoint = point;
});
},
//
center: markerPoint,
zoom: 10.0,
// this is required to disable rotation of the map
// the map will behave wierd when you rotate it if it's deleted
// the map will not scroll properly and not place markers at the exact locations.
// if the below line in removed
interactiveFlags: InteractiveFlag.all & ~InteractiveFlag.rotate,
),
nonRotatedChildren: [
TileLayer(
urlTemplate: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
subdomains: const ['a', 'b', 'c'],
),
MarkerLayer(
markers: [
Marker(
width: 100.0,
height: 100.0,
point: markerPoint,
builder: (ctx) => const Icon(
Icons.location_on,
color: Colors.red,
size: 40,
),
),
],
),
],
),
SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Card(
child: TextField(
decoration: const InputDecoration(
prefixIcon: Icon(Icons.location_on_outlined),
hintText: "Search for a location",
contentPadding: EdgeInsets.all(16.0),
),
onTap: () async {
// This is here for debugging only, kindly ignore
await requestPermission();
},
),
),
],
),
),
),
],
);
}
hope you are calling the get current location api in the initState() method
eg :
#override
void initState() {
super.initState();
fetchCurrentLocation();
}
void fetchCurrentLocation() async{
//calling the api
var currentLocation = await _locationService.currentLocation;
//setState will update the values in real time
setState(() {
markerPoint = currentLocation
});
}
I have a map in flutter where I have to commute the user to a specific point using directions. The red marker on the map when on pressed automatically shows directions on the bottom right but I want to show an arrow head to the user to click the directions on the bottom right because user may not notice it by themselves: https://imgur.com/a/lv9Xq9T
This is the code snippet :
void getLocation() async {
var location = await currentLocation.getLocation();
currentLocation.onLocationChanged.listen((LocationData loc) {
mapcontroller.animateCamera(CameraUpdate.newCameraPosition(CameraPosition(
target: LatLng(loc.latitude ?? 0.0, loc.longitude ?? 0.0), zoom: 5)));
setState(() {
clat = loc.latitude;
clng = loc.longitude;
_markers.addAll({
Marker(
markerId: const MarkerId('Shopkeeper Position'),
icon: BitmapDescriptor.defaultMarker,
// position: LatLng(20.7708612, 73.7235274))
position: LatLng(
widget.latitude,
widget.longitude,
),
onTap: () {
print("");
print("");
print("Marker pressed");
print("");
print("");
Container(
alignment: Alignment.bottomCenter,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Get Directions",
style: GoogleFonts.roboto(
fontSize: 40,
fontWeight: FontWeight.w800,
color: Colors.blue,
),
),
Image.asset(
'assets/arrowHead.gif',
width: 200,
height: 200,
),
],
),
);
},
)
});
});
getPolypoints();
});
}
All i get when I tap on the marker are the print statements. I would want to display the row widget as well. How can i do this ?
You need to move your directions container and show/hide depending on the onTap.
Something like this:
isTapped ?? directionsContainer : Container() // empty container if isTapped is false
Update your onTap: to update state with a boolean:
setState(() {
isTapped = !isTapped;
})
Im a newbie in flutter. I'm making a project and I want to know how can I render the list of points using latlong plugin from flutter inside flutter map. I was able to render the first point but unable to show the other points in the list. Can you please guide me or correct my code.
Widget _mapBuilder(BuildContext context) {
final List<LatLng> _mapPoints = [
LatLng(9.7, 123.1),
LatLng(10.7, 124.9),
LatLng(11.7, 125.05)
];
return FlutterMap(
options: MapOptions(
center: _mapPoints[1],
zoom: 16.0,
),
layers: [
TileLayerOptions(
urlTemplate: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
subdomains: ['a', 'b', 'c'],
attributionBuilder: (_) {
return const Text("© OpenStreetMap contributors");
},
),
MarkerLayerOptions(markers: [
for (var point in _mapPoints) ...[
Marker(
width: 15.0,
height: 15.0,
point: point,
builder: (ctx) => Container(
decoration: BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.circular(50.0),
border: Border.all(color: Colors.white, width: 2)),
),
),
]
]),
],
);
You can create markers list like this and use that list in Markers parameters required in marker layer.
final List<LatLng> _mapPoints = [
LatLng(12.9, 77.8),
LatLng(12.1, 77.2),
LatLng(12.5,77.4),
];
for (LatLng i in _mapPoints){
lister.add(Marker(point: i, builder:(ctx) =>
Container(child: Column(
children: [
Icon(Icons.add,size: 40,),
Text("data",style: TextStyle(fontSize: 12),)
],
),
)));
}
It should be very simple, but I can't seem to find how to do it.
In Flutter / openstreetmap, I need to: (1) put a marker on the map by tapping a map and/or clicking a button; (2) connect two of these markers with a line(s).
Any ideas would be appreciated.
1) For adding markers:
List<Marker> markers = [];
Inside Build method:
FlutterMap(
mapController: _mapController,
options: MapOptions(
center: LatLng(41.238250, 69.342939),
zoom: 9.6,
onTap: (latlng) {
setState(() {
markers.add(
Marker(
width: 150.0,
height: 150.0,
point: latlng,
builder: (ctx) => const Icon(
Icons.location_on,
color: Colors.red,
size: 35.0,
),
),
);
});
}),
layers: [
MarkerLayerOptions(
markers: [
for (int i = 0; i < markers.length; i++) markers[i]
],
),
],
),
2) If you want to get directions between two points, you can use this service, it's free. http://project-osrm.org
The link I am using for getting directions between two points.
https://api.openrouteservice.org/v2/directions/driving-car?api_key=$OSRM_API_KEY&start=${origin.longitude},${origin.latitude}&end=${destination.longitude},${destination.latitude}
It takes, API Key and starting point lat-long and ending point lat-long.
Response gives you multiple lat-long points, and if you give these points to polyLine parameter of map, it will draw you a road line between two points
Let me know if you need any clarification on some part of my answer
along with greeting you, I wanted to ask you if someone has been able to show an InfoWindow in the flutter map maker, or create a container that is floating so that it appears next to the maker, in google map if possible.
new Marker
(
width: 45.0,
height: 45.0,
point: new LatLng(-25.963678, -51.240657),
builder: (ctx) =>
new Container //here infoWindow or Float Container
(
//child: new FlutterLogo(),
child: IconButton
(
icon: Icon(Icons.location_on),
color: Colors.blue,
iconSize: 45.0,
tooltip: "prueba",
onPressed: ()
{
print("test press");
},
)
),
),
Thank you very much for the help as always.
You cannot set a widget as the marker info-window in any of the flutter map plugins. You can only set the title and text of the info-window in the google maps plugins.
You could turn the map info-window off, center the map on the marker if the user clicks on it, and add some code to show a custom dialog at the approximate center of the screen. You would have to use the flutter Stack widget.
Stack(
children:[
Map(
markers: [Marker(/*no info-window*/, onTap: (){
setState((){ _opacity = 1; });
})],
onMapMove: (){
setState((){ _opacity = 0; });
}
),
Opacity(
opacity: _opacity,
child: /*custom info-window*/,
),
],
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
),
Use custom_info_window package as follows:
Step 1: Initialise CustomInfoWindowController.
CustomInfoWindowController _customInfoWindowController = CustomInfoWindowController();
Step 2: Call CustomInfoWindowController's addInfoWindow from marker's onTap function.
Marker(
markerId: MarkerId("marker_id"),
position: _latLng,
onTap: () {
_customInfoWindowController.addInfoWindow(
<YOUR CUSTOM WIDGET>,
_latLng,
);
},
)
Step 3: Use GoogleMap Widget with Stack.
Stack(
children: <Widget>[
GoogleMap(
onTap: (position) {
_customInfoWindowController.hideInfoWindow();
},
onCameraMove: (position) {
_customInfoWindowController.onCameraMove();
},
onMapCreated: (GoogleMapController controller) async {
_customInfoWindowController.googleMapController = controller;
},
markers: _markers,
initialCameraPosition: CameraPosition(
target: _latLng,
zoom: _zoom,
),
),
CustomInfoWindow(
controller: _customInfoWindowController,
height: 75,
width: 150,
offset: 50,
),
],
)
Call _customInfoWindowController.hideInfoWindow(); inside GoogleMap's onTap to hide CustomInfoWindow when clicking on map but not on the marker.
Call _customInfoWindowController.onCameraMove(); to maintain CustomInfoWindow's position relative to marker. [IMPORTANT]
Assign _customInfoWindowController.googleMapController = controller; inside onMapCreated. [IMPORTANT]
Add CustomInfoWindow as next child to float this on top GoogleMap.