Flutter Google Maps and Location

There are many times when you are making an application and you may need to use Maps as well as Location to work around. What can be the better map than the Google Maps itself?

Before we start, it is better to clear what we will be needing:

The followings can be installed by keeping the package name along with the version in the pubspec.yaml file, found in the root.

Starting off, the permission can be asked at any given time but the package must be imported first. It can be at the very beginning of the application or when you are actually trying to access the map. For this tutorial, I placed a button in the home that will specifically ask for.

import 'package:google_maps_flutter/google_maps_flutter.dart';

Before the permission is asked, the permission tag for location has to be added in the AndroidManifest.xml file. The file can be found at: app\src\main\AndroidManifest.xml

Add the following statement right after the opening tag of manifest.

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

As well as the Google API Key (you can get it from here) in the application tag before activity tag. Like this:

<meta-data android:name="com.google.android.geo.API_KEY" android:value="YOUR-API-KEY"/>

Then the following function should be called.

Future doLocationPermissionAsk() async {
Map<PermissionGroup, PermissionStatus> permissions = await PermissionHandler().requestPermissions([PermissionGroup.location]);
}

The above function is called by the following button. If permission has been granted already, nothing happens. Otherwise it will bring the popup question.

RaisedButton(
  child: Text('Ask for permission'),
  onPressed: () {
    doLocationPermissionAsk();
  },
),

For keeping things fairly simply, I created another screen for the map. The first import is the Google Map itself along with the Location package. Dart Async is used since a lot of calls will keep happening meanwhile the foreground looks smooth.

import 'dart:async';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:location/location.dart';

The following objects are instantiated:

//A controller for GoogleMaps widget
Completer<GoogleMapController> _controller = Completer();
Location location = Location();

//The marker for user's selected location
Map<MarkerId, Marker> markers = <MarkerId, Marker>{};
CameraPosition cameraPosition;

//The initial camera position.
static final CameraPosition _kGooglePlex = CameraPosition(
    target: LatLng(37.42796133580664, -122.085749655962),
    zoom: 14.4746,
);

//For updating the location when the camera position is changed.
void updateMarker(CameraPosition position){
    final MarkerId markerId = MarkerId("selectedLocation");
    Marker marker = Marker(
      markerId: markerId,
      position: LatLng(position.target.latitude, position.target.longitude),
      onTap: (){
        print("Location selected");
      }
    );

//The marker needed to be displayed on the map
markers[markerId] = marker;

The build method will be a normal one with a Scaffold inside.

@override
Widget build(BuildContext context) {
return new Scaffold(
      appBar: AppBar(
        title: Text('The Google Maps Tutorial'),
      ),
      body: GoogleMap(
        mapType: MapType.normal,
        initialCameraPosition: _kGooglePlex,
        myLocationEnabled: true,
        markers: Set<Marker>.of(markers.values),
        onCameraMove: (position){
          setState(() {
            cameraPosition = position;
          });
          updateMarker(cameraPosition);
        },
        onMapCreated: (GoogleMapController controller) {
          _controller.complete(controller);
        },
      ),
      floatingActionButton: FloatingActionButton.extended(
        onPressed: (){
          Navigator.pop(context, cameraPosition);
        },
        label: Text('Location confirmed!')
      ),
    );
}

In the above code, GoogleMaps is a widget has the following properties and events (along with why).

  • mapType be a hybrid, satellite or normal with no satellite images.
  • initialCameraPosition where the map should start showing from.
  • myLocationEnabled the icon for showing your location should be shown or not.
  • markers those red pins shown on the map for some user selected location. We will be using this for showing the user selected location.
  • onCameraMove will occur when the camera is (view) is changed and continues to be called until the camera movement stops.
  • onMapCreated will occur right after the map is loaded completely and it will update our _controller that the map is completely loaded.

Then we have a button for confirming the location the user has selected. This can be done in the marker by using the onTap event. That might also make the user confuse. That floating action button (FAB) is popping the current screen and passing back the selected coordinates back to the main page.

The file would look like this.

import 'dart:async';

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

class MapScreen extends StatefulWidget {
  @override
  _MapScreenState createState() => _MapScreenState();
}

class _MapScreenState extends State<MapScreen> {

  Completer<GoogleMapController> _controller = Completer();
  Location location = Location();
  Map<MarkerId, Marker> markers = <MarkerId, Marker>{};
  CameraPosition cameraPosition;

  static final CameraPosition _kGooglePlex = CameraPosition(
    target: LatLng(37.42796133580664, -122.085749655962),
    zoom: 14.4746,
    );

  void updateMarker(CameraPosition position){
    final MarkerId markerId = MarkerId("selectedLocation");
    Marker marker = Marker(
      markerId: markerId,
      position: LatLng(position.target.latitude, position.target.longitude),
      onTap: (){
        print("Location selected");
      }
    );

    markers[markerId] = marker;
  }

  @override
  Widget build(BuildContext context) {

    return new Scaffold(
      appBar: AppBar(
        title: Text('The Google Maps Tutorial'),
      ),
      body: GoogleMap(
        mapType: MapType.normal,
        initialCameraPosition: _kGooglePlex,
        myLocationEnabled: true,
        onCameraMove: (position){
          //debugPrint("Camera Position Ghulam Mustafa $position ");
          setState(() {
            cameraPosition = position;
          });
          updateMarker(cameraPosition);
        },
        markers: Set<Marker>.of(markers.values),
        onMapCreated: (GoogleMapController controller) {
          _controller.complete(controller);
        },
      ),
      floatingActionButton: FloatingActionButton.extended(
        onPressed: (){
          Navigator.pop(context, cameraPosition);
        },
        label: Text('Location confirmed!'),
      ),
    );
  }
}

While on the main screen, you can call the mapScreen like this for getting the coordinates.

CameraPosition cameraPosition = await Navigator.of(context).push(MaterialPageRoute(builder: (context) => MapScreen()));

The code for the following can be found in GitHub.

A word of advice: If you are trying to add permissions, location, or those advanced level things, always uninstall the entire application from your phone from one phase to another.

For example, if you run the application without Maps or Location and then add Location later. This location may not work until you uninstall and install the application again.

Do not pull out your hair because of that.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s