Reputation: 119
I'm using Flutter's Geolocator and Google Maps packages to determine a device's location. I utilize the Circular Progress Bar to wait for the current location to be determined. Once determined, Google Maps loads with the device's location identified.
When the application loads, the circular progress bar is displayed but the map is not loaded despite the notification being displayed and accepted to use location services; the app hangs on the circular progress bar. I don't believe this to be an API issue as I have had success loading the map with coordinates specified in InitialCameraPosition.
Is the device's location not being determined which is the cause for the map to not load with the location indicated?
I've tried running the app on both Android emulator and a physical device without success.
Android Manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="smartkart.app.com.coffee">
<!-- io.flutter.app.FlutterApplication is an android.app.Application
that
calls FlutterMain.startInitialization(this); in its onCreate
method.
In most cases you can leave this as-is, but you if you want to
provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:name="io.flutter.app.FlutterApplication"
android:label="coffee"
android:icon="@mipmap/ic_launcher">
<meta-data android:name="com.google.android.geo.API_KEY"
android:value="API KEY HERE"/>
<activity../>
Maps Screen
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:geolocator/geolocator.dart';
class FirstScreen extends StatefulWidget {
const FirstScreen({Key key}) : super(key: key);
@override
State<FirstScreen> createState() => _FirstScreen();
}
class _FirstScreen extends State<FirstScreen> {
GoogleMapController mapController;
var currentLocation;
@override
void initState(){
super.initState();
Geolocator().getCurrentPosition().then((currloc){
currentLocation = currloc;
});
}
@override
Widget build(BuildContext context) {
return currentLocation == null ? Container(
alignment: Alignment.center,
child: Center(
child: CircularProgressIndicator(),
),
):
Stack(
children: <Widget>[
GoogleMap(
initialCameraPosition:
CameraPosition(target: LatLng(currentLocation.latitude,
currentLocation.longitude), zoom: 10),
onMapCreated: _onMapCreated,
myLocationEnabled: true,
mapType: MapType.normal,
),
],
);
}
void _onMapCreated(GoogleMapController controller) {
setState(() {
mapController = controller;
});
}
}
I expect the notification to use location services to appear while the circular progress bar is displayed. Once the location is determined, the InitialCameraPosition displays the device's location on the map.
Upvotes: 3
Views: 19774
Reputation: 1049
Use GeoLocator package with google_maps_flutter
Sample Code:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:geolocator/geolocator.dart';
class MapScreen extends StatefulWidget {
@override
State<MapScreen> createState() => MapScreenState();
}
class MapScreenState extends State<MapScreen> {
LatLng initPosition = LatLng(0, 0); //initial Position cannot assign null values
LatLng currentLatLng= LatLng(0.0, 0.0); //initial currentPosition values cannot assign null values
LocationPermission permission = LocationPermission.denied; //initial permission status
Completer<GoogleMapController> _controller = Completer();
@override
void initState() {
super.initState();
getCurrentLocation();
checkPermission();
}
//checkPersion before initialize the map
void checkPermission() async{
permission = await Geolocator.checkPermission();
}
// get current location
void getCurrentLocation() async{
await Geolocator.getCurrentPosition().then((currLocation) {
setState(() {
currentLatLng =
new LatLng(currLocation.latitude, currLocation.longitude);
});
});
}
//call this onPress floating action button
void _currentLocation() async {
final GoogleMapController controller = await _controller.future;
getCurrentLocation();
controller.animateCamera(CameraUpdate.newCameraPosition(
CameraPosition(
bearing: 0,
target: currentLatLng,
zoom: 18.0,
),
));
}
//Check permission status and currentPosition before render the map
bool checkReady(LatLng? x, LocationPermission? y) {
if (x == initPosition || y == LocationPermission.denied || y == LocationPermission.deniedForever) {
return true;
} else {
return false;
}
}
@override
Widget build(BuildContext context) {
print(permission);
print("Current Location --------> " +
currentLatLng.latitude.toString() +
" " +
currentLatLng.longitude.toString());
return MaterialApp(
//remove debug banner on top right corner
debugShowCheckedModeBanner: false,
home: new Scaffold(
//ternary operator use for conditional rendering
body: checkReady(currentLatLng, permission)
? Center(child: CircularProgressIndicator())
//Stack : place floating action button on top of the map
: Stack(children: [
GoogleMap(
myLocationEnabled: true,
myLocationButtonEnabled: false,
zoomControlsEnabled: false,
mapType: MapType.normal,
initialCameraPosition: CameraPosition(target: currentLatLng),
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
},
),
//Positioned : use to place button bottom right corner
Positioned(
bottom: 0,
right: 0,
child: Container(
margin: EdgeInsets.all(15),
child: FloatingActionButton(
onPressed: _currentLocation,
child: Icon(Icons.location_on)),
),
),
]),
),
);
}
}
Upvotes: 0
Reputation: 7716
You seem to be missing setState
in your initState
.
It should look like this:
@override
void initState(){
super.initState();
Geolocator().getCurrentPosition().then((currloc){
setState((){
currentLocation = currloc;
});
});
}
Upvotes: 0
Reputation: 928
Try the following code as a solution. You can modify the map widget to your use case:
import 'package:flutter/cupertino.dart';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
class Map extends StatefulWidget {
@override
_MapState createState() => _MapState();
}
class _MapState extends State<Map> {
Completer<GoogleMapController> controller1;
//static LatLng _center = LatLng(-15.4630239974464, 28.363397732282127);
static LatLng _initialPosition;
final Set<Marker> _markers = {};
static LatLng _lastMapPosition = _initialPosition;
@override
void initState() {
super.initState();
_getUserLocation();
}
void _getUserLocation() async {
Position position = await Geolocator().getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
List<Placemark> placemark = await Geolocator().placemarkFromCoordinates(position.latitude, position.longitude);
setState(() {
_initialPosition = LatLng(position.latitude, position.longitude);
print('${placemark[0].name}');
});
}
_onMapCreated(GoogleMapController controller) {
setState(() {
controller1.complete(controller);
});
}
MapType _currentMapType = MapType.normal;
void _onMapTypeButtonPressed() {
setState(() {
_currentMapType = _currentMapType == MapType.normal
? MapType.satellite
: MapType.normal;
});
}
_onCameraMove(CameraPosition position) {
_lastMapPosition = position.target;
}
_onAddMarkerButtonPressed() {
setState(() {
_markers.add(
Marker(
markerId: MarkerId(_lastMapPosition.toString()),
position: _lastMapPosition,
infoWindow: InfoWindow(
title: "Pizza Parlour",
snippet: "This is a snippet",
onTap: (){
}
),
onTap: (){
},
icon: BitmapDescriptor.defaultMarker));
});
}
Widget mapButton(Function function, Icon icon, Color color) {
return RawMaterialButton(
onPressed: function,
child: icon,
shape: new CircleBorder(),
elevation: 2.0,
fillColor: color,
padding: const EdgeInsets.all(7.0),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: _initialPosition == null ? Container(child: Center(child:Text('loading map..', style: TextStyle(fontFamily: 'Avenir-Medium', color: Colors.grey[400]),),),) : Container(
child: Stack(children: <Widget>[
GoogleMap(
markers: _markers,
mapType: _currentMapType,
initialCameraPosition: CameraPosition(
target: _initialPosition,
zoom: 14.4746,
),
onMapCreated: _onMapCreated,
zoomGesturesEnabled: true,
onCameraMove: _onCameraMove,
myLocationEnabled: true,
compassEnabled: true,
myLocationButtonEnabled: false,
),
Align(
alignment: Alignment.topRight,
child: Container(
margin: EdgeInsets.fromLTRB(0.0, 50.0, 0.0, 0.0),
child: Column(
children: <Widget>[
mapButton(_onAddMarkerButtonPressed,
Icon(
Icons.add_location
), Colors.blue),
mapButton(
_onMapTypeButtonPressed,
Icon(
IconData(0xf473,
fontFamily: CupertinoIcons.iconFont,
fontPackage: CupertinoIcons.iconFontPackage),
),
Colors.green),
],
)),
)
]),
),
);
}
}
Upvotes: 6