Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How To Set Initial Camera Position To The Current Device's Latitude and Longitude Using Google Maps For Flutter

I am using google maps flutter plugin for my App. I want the initial camera position target (the LatLng) to be exactly equal to the current device's latitude and longitude so that the camera on startup shows where the user currently is. However, I am running into issues trying to do this. I have tried using the Location and Geolocator packages but there is no clear cut example on how to do what I want to achieve.

When I try to use currentLocation.latitude and currentLocation.longitude for the Location package as the values for the Latlng in the camera target I am running into the below error.

"only static members can be accessed by initializers"

Frankly I don't know what that means in this context. I have read some examples but none clearly implements what I really want to achieve

import 'package:flutter/cupertino.dart';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:location/location.dart';


class Map extends StatefulWidget {
  @override
  State<Map> createState() => MapState();
}

class MapState extends State<Map> {
  Completer<GoogleMapController> _controller = Completer();
  var currentLocation = LocationData;

  var location = new Location();

 Future _getLocation() async {
    try {
      location.onLocationChanged().listen((LocationData currentLocation) {
        print('Latitude:${currentLocation.latitude}');
        print('Longitude:${currentLocation.longitude}');
        return LatLng(currentLocation.latitude, currentLocation.longitude);
      });
    } catch (e) {
     print('ERROR:$e');
      currentLocation = null;
    }

  }
  static final CameraPosition _currentPosition = CameraPosition(
    target: LatLng(currentLocation.latitude  ,  currentLocation.longitude),
    zoom: 14.4746,
  );

  @override
  void initState() {
    _getLocation();
    super.initState();
  }


  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: GoogleMap(
        mapType: MapType.normal,
        initialCameraPosition: _currentPosition,
        zoomGesturesEnabled: true,
        myLocationButtonEnabled: true,
        rotateGesturesEnabled: true,
        tiltGesturesEnabled: true,
        onMapCreated: (GoogleMapController controller) {
          _controller.complete(controller);
        },
      ),

    );
  }


}

That is my code snippet producing the error on the _currentPosition final which represents Camera position am equating it to current device's latitude and longitude using locator package but Flutter is complaining. I don't know how to do it correctly. I want the latlng target to be the latlng of the device

like image 354
K.chim Avatar asked Aug 26 '19 11:08

K.chim


2 Answers

The issue concerning the error when displaying the map widget while getting the user current location is that, getting the user's actual current location is an asynchronous operation and thus the during that whole process initial position will be null thus we make a conditional that runs as we wait for the async operation to complete then display the map when then the value will be non-null. I have refactored the code and used the geolocator package instead

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),
                  ],
                )),
          )
        ]),
      ),
    );
  }
}
like image 75
K.chim Avatar answered Oct 04 '22 03:10

K.chim


GeoLocator API has been changed with latest upgraded Geolocator is no longer used. Instead GeolocatorPlatform is new keyword to access current postion as per latest updates

LatLng currentPostion;

void _getUserLocation() async {
        var position = await GeolocatorPlatform.instance
            .getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
    
        setState(() {
          currentPostion = LatLng(position.latitude, position.longitude);
        });
      }

Use currentPostion in your googlemap. (define Latlag currentPosition);

GoogleMap(
             // onMapCreated: _onMapCreated,
             initialCameraPosition: CameraPosition(
               target: currentPostion,
               zoom: 10,
             ),  
           ),
   
like image 44
Mohd Danish Khan Avatar answered Oct 04 '22 04:10

Mohd Danish Khan