I want to follow user location continuously in my application. For this reason, I want to execute getLocaiton bloc event continuously in my main page. How can I do that?
Here is the my getLocation event;
GetLocationState get initialState => GetLocationState(saveUserCurrentLocation: initialPosition );
Stream<GetLocationState> mapEventToState(LocationEvent event) async*{
if (event is GetLocation){
userLocation.getLocation().then((l){
currentLatLng = LatLng(l.latitude, l.longitude);
});
yield GetLocationState(saveUserCurrentLocation: currentLatLng);
}
}
And this my my main page
initialCameraPosition:
CameraPosition(target: initialPosition, zoom: 10),
mapType: MapType.terrain,
onMapCreated: _onMapCreated,
myLocationEnabled: true,
),
floatingActionButton: FloatingActionButton(
onPressed: () {
_locationBloc.add(GetLocation());
},
),
),
);
});
}
How can I run code continuously in the background, without using onPress event?
use a Timer inside initState() (make you widget stateful if it isn't):
Timer(Duration(seconds: 5), (){
_locationBloc.add(GetLocation());
});
Related
I tried to build an application, which shows the current user location. In order to achieve this goale, I used Google-Map and location plug-in. I tried a sample I found in the internet, but I get an error and don't know why... I think I did it the same like the guy in the video did it...
This is the ode I tried:
void _onMapCreated(GoogleMapController controller) {
_controller = controller;
_location.onLocationChanged().listen((l) {
_controller.animateCamera(CameraUpdate.newCameraPosition(
CameraPosition(target: LatLng(l.latitude, l.lomgitude), zoom: 10)));
});
}
child: GoogleMap(
markers: markers,
initialCameraPosition: position,
mapType: MapType.hybrid,
onMapCreated: _onMapCreated,
myLocationButtonEnabled: true,
),
This is the error I get:
Compiler message:
lib/main.dart:42:32: Error: 'onLocationChanged' isn't a function or method and can't be invoked.
_location.onLocationChanged().listen((l) {
^^^^^^^^^^^^^^^^...
Does anybody find my mistake?
You can remove () of onLocationChanged()
please change from
_location.onLocationChanged().listen((l) {
_controller.animateCamera(CameraUpdate.newCameraPosition(
CameraPosition(target: LatLng(l.latitude, l.lomgitude), zoom: 10)));
});
to
_location.onLocationChanged.listen((l) {
_controller.animateCamera(CameraUpdate.newCameraPosition(
CameraPosition(target: LatLng(l.latitude, l.lomgitude), zoom: 10)));
});
I am having zero luck turning off the floating action button which exists on the Google maps view in Flutter. I have tried restarting the app, hotreload, delete/reinstall, no luck.
Here's my code:
return Card(
child: GoogleMap(
compassEnabled: false,
mapToolbarEnabled: false,[![enter image description here][1]][1]
padding: EdgeInsets.all(1),
mapType: MapType.normal,
myLocationButtonEnabled: false,
myLocationEnabled: false,
initialCameraPosition: _curCamera,
markers: Set<Marker>.of(_markers),
polylines: Set<Polyline>.of(_polylines),
onMapCreated: (GoogleMapController controller) async {
staticMapController = controller;
positionList = await tracksDB.getListOfPositions(widget.trackID);
setState(() {
_polylines.add(Polyline(
polylineId: PolylineId('track1'),
visible: true,
points: positionList,
color: Colors.red,
));
});
},
),
);
Latest package version fixed the problem. google_maps_flutter: ^1.0.3
I am trying to load googlemap(google_maps_flutter 0.5.25+1
library) on a dialog window using the following method
_loadMapDialog() {
try {
if (_currentPosition.latitude == null) {
Toast.show("Location not available. Please wait...", context,
duration: Toast.LENGTH_LONG, gravity: Toast.BOTTOM);
_getLocation(); //_getCurrentLocation();
return;
}
_controller = Completer();
_userpos = CameraPosition(
target: LatLng(latitude, longitude),
zoom: 14.4746,
);
markers.add(Marker(
markerId: markerId1,
position: LatLng(latitude, longitude),
infoWindow: InfoWindow(
title: 'New Location',
snippet: 'Delivery Location',
)));
showDialog(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return AlertDialog(
title: Text("Select Your Location"),
titlePadding: EdgeInsets.all(5),
content: Text(curaddress),
actions: <Widget>[
Container(
height: screenHeight / 1.4 ?? 600,
width: screenWidth ?? 400,
child:
GoogleMap(
mapType: MapType.normal,
initialCameraPosition: _userpos,
markers: markers,
onMapCreated: (controller) {
_controller.complete(controller);
},
onTap: _loadLoc,
),
)
],
);
},
);
},
);
} catch (e) {
print(e);
return;
}
}
void _loadLoc(LatLng loc) async{
setState(() {
print("insetstate");
markers.clear();
latitude = loc.latitude;
longitude = loc.longitude;
label = latitude.toString();
_getLocationfromlatlng(latitude,longitude);
_home = CameraPosition(
target: loc,
zoom: 14,
);
markers.add(Marker(
markerId: markerId1,
position: LatLng(latitude, longitude),
infoWindow: InfoWindow(
title: 'New Location',
snippet: 'Delivery Location',
)));
});
_userpos = CameraPosition(
target: LatLng(latitude, longitude),
zoom: 14.4746,
);
_newhomeLocation();
}
Future<void> _newhomeLocation() async {
gmcontroller = await _controller.future;
gmcontroller.animateCamera(CameraUpdate.newCameraPosition(_home));
Navigator.of(context).pop(false);
_loadMapDialog();
}
I did manage to load the map in my AlertDialog. The problem is I need to be able to select new location on the map remove the previous marker and show new marker on the map, however marker is not showing on the map unless the app perform hot reload. For now I'm using kind a stupid way which pop the current alertdialog and show it again using _loadMapDialog() method to reload widget. I did try to use flutter_places_dialog library but seems I got some problem with activity return result error.
flutter newb here be kind..
Problem is you are updating marker with setState provided by StatefulWidget.
But Dialog is updating its state with setState provided by StatefulBuilder.
Solution is add StatefulBuilder's setState to onTap callback function's parameter and use it inside _loadLoc function like my code.
List<Marker> markers = [];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('GoogleMap'),
),
body: Center(
child: RaisedButton(
onPressed: () {
showDialog(
context: (context),
builder: (context) {
return StatefulBuilder(builder: (context, newSetState) {
return AlertDialog(
title: Text('Google Map'),
content: GoogleMap(
initialCameraPosition: CameraPosition(
target: LatLng(11.004556, 76.961632), zoom: 14),
markers: markers.toSet(),
onTap: (newLatLng) {
addMarker(newLatLng, newSetState);
},
),
);
});
});
},
),
),
);
addMarker(latLng, newSetState)
{
newSetState(() {
markers.clear();
markers.add(Marker(markerId: MarkerId('New'), position: latLng));
});
}
I'm trying to add a google map widget with custom icons on the screen.
For that reason, I need to use the FutureBuilder to get the icons BitmapDescriptor.fromAssetImage before I try to render the map.
This method is an async one so I have thrown it into the FutureBuilder so the entire widget waits until all my icons are allocated.
The app works, but the problem is that it has this quick but very noticeable screen flick, which makes the area black. I have a progress indicator but it does not matter, the black screen always shows up.
#override
Widget build(BuildContext context) {
return Consumer <RestaurantsData>(
builder: (context, _restaurantsData, __) => FutureBuilder<bool>(
future: _prepareWidget(),
builder: (BuildContext buildContext, AsyncSnapshot<bool> snapshot) {
if (snapshot.connectionState == ConnectionState.done
&& snapshot.data
&& snapshot.hasData) {
return googleMap(_restaurantsData);
}
logger.d("Map widget still processing");
return Center(
// Display Progress Indicator
child: CircularProgressIndicator(
backgroundColor: Colors.white,
),
);
})
);
}
Widget googleMap(RestaurantsData _restaurantsData){
return Container(
child: GoogleMap(
mapType: MapType.normal,
myLocationEnabled: true,
myLocationButtonEnabled: true,
mapToolbarEnabled: false,
zoomGesturesEnabled: true,
rotateGesturesEnabled: true,
initialCameraPosition: CameraPosition(
target: _defaultLatLng,
zoom: _defaultZoom
),
onMapCreated: (GoogleMapController controller) {
_controller = controller;
},
onTap: (latLng) {
if (bottomSheetCtrl != null) {
bottomSheetCtrl.close();
bottomSheetCtrl = null;
}
},
markers: createRestaurantMarkers(_restaurantsData),
gestureRecognizers: _gestureRecognizers
)
);
}
Set<Marker> createRestaurantMarkers(RestaurantsData restaurantsData) {
return restaurantsData.getRestaurants()
.map((item) =>
Marker(
position: item.latLng,
markerId: MarkerId("${item.id}|${item.name}"),
icon: getIconFor(item),
onTap: () {
logger.i("Marker clicked: ${item.id}, ${item.name}");
showRestaurantDetails(context, item);
restaurantsData.selectOne(item);
}
))
.toSet();
}
The prepare widget call is as follows:
Future<bool> _prepareWidget() async {
_markerIcon = await BitmapDescriptor.fromAssetImage(
ImageConfiguration(devicePixelRatio: 2.5),
marker
);
_selectedMarkerIcon = await BitmapDescriptor.fromAssetImage(
ImageConfiguration(devicePixelRatio: 2.5),
markerSelected
);
_disabledMarkerIcon = await BitmapDescriptor.fromAssetImage(
ImageConfiguration(devicePixelRatio: 2.5),
disabledMarker
);
_disabledSelectedMarkerIcon = await BitmapDescriptor.fromAssetImage(
ImageConfiguration(devicePixelRatio: 2.5),
disabledMarkerSelected
);
return Future.value(_markerIcon != null
&& _selectedMarkerIcon != null
&& _disabledMarkerIcon != null
&& _disabledSelectedMarkerIcon != null
);
}
I have 4 icons that are always static and available from the start of the app.
Any ideas on how to fix this?
I'm fairly new to flutter so this issue maybe because of something that I'm doing wrong.
I fixed the flickering by building the Future using FuturBuilder and passing it as a Provider in an ancestor widget. It's build before all main widgets and only once.
In a parent widget:
return MultiProvider(
providers: [
FutureProvider<MapMarkerProvider>(
lazy: false,
create: (_) async => MapMarkerProvider().loadMarkers() //<- Async Action loading icons.
),
],
child: Scaffold(
appBar: new EmptyAppBar(),
body: Container(
....
)
)
);
}
I'm trying to display Google maps inside a dialog box and for the first time it pops up as expected, however the second time it throws and exception: StateError (Bad state: Future already completed).
Completer<GoogleMapController> _controller = Completer();
_displayDialog(){
Alert(
context: context,
style: alertStyle,
title: "Here are your results:",
content: Column(
children: <Widget>[
Container(
width: 200.0,
height: 200.0,
child: GoogleMap(
//mapType: MapType.hybrid,
initialCameraPosition: _kGooglePlex,
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller); //throws here in this line
},
),
),
],
),
Here is a gif to summarize whats happening
Im using rflutter_alert: ^1.0.3 for the dialog box,
and google_maps_flutter: ^0.5.21+15 for Maps.
Thanks in advance!
this verifies if previously I already called "completer ()" if so, you don't need to call "completer ()" again, and just skip it in your code
onMapCreated: (GoogleMapController controller) {
if (!_controller.isCompleted) {
//first calling is false
//call "completer()"
_controller.complete(controller);
}else{
//other calling, later is true,
//don't call again completer()
}
}
I think that the problem is because you are trying to complete a Completer twice which is not allowed. What I did bellow was to create a new Completer each time you call _displayDialog().
_displayDialog(){
Completer<GoogleMapController> _controller = Completer();
Alert(
context: context,
style: alertStyle,
title: "Here are your results:",
content: Column(
children: <Widget>[
Container(
width: 200.0,
height: 200.0,
child: GoogleMap(
//mapType: MapType.hybrid,
initialCameraPosition: _kGooglePlex,
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller); //throws here in this line
},
),
),
],
),