New2Css
New2Css

Reputation: 119

Flutter Google Maps not determining current location of device

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

Answers (3)

Lojith Vinsuka
Lojith Vinsuka

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

Victor Eronmosele
Victor Eronmosele

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

K.chim
K.chim

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

Related Questions