Using Google Maps

If you want to conveniently convey details of places, directions and routes to the end-user, Google Maps is an essential part of your app. Luckily, there is an official google_maps_flutter available for Flutter.

  1. Creating a GCP project
  2. You will need a GCP project to get access to the Google Maps API and generate an API key.

    To create a new GCP project, follow the steps below:

    1. Go to the GCP console

    2. Go to the Project Selection dialog box and click New Project.

    3. Enter a name for your project and click Create.

    4. This will create a new GCP Project.

  3. Enabling APIs
  4. In order to use Google Maps in your app, you will need to enable Maps SDK for both platforms.

    1. Go to APIs & Services from the left menu and select Library.

    2. Now, search for Maps and enable Maps SDK for both platforms.

    3. You will also need the Directions API while drawing the routes. So enable that as well.



  5. Generating an API key
  6. You will need an API key for integrating Google Maps with your app.

    1. Go to APIs & Services from the left menu and select Credentials.

    2. Click CREATE CREDENTIALS and select API key.

    3. This will generate an API key that you will need in the next step.

  7. Set up the Flutter project
    • Create a new Flutter project.

    • flutter create flutter_maps
    • Open the project using your favorite IDE. For opening with VS Code:

    • code flutter_maps
    • Add the google_maps_flutter plugin to the pubspec.yaml file:

    • google_maps_flutter: ^2.0.6

    Android setup

    Go to android/app/build.gradle and set the minSdkVersion to 20:

    android {

    defaultConfig {

    minSdkVersion 20

    }

    }



    Navigate to the file android/app/src/main/AndroidManifest.xml and add the following code snippet inside the application tag:

    <!-- Add your Google Maps API Key here -->
    <meta-data android:name="com.google.android.geo.API_KEY"
                   android:value="YOUR KEY HERE"/>


    You will also need the location access in the app. Add the following permission in the same file inside the manifest tag:


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



    iOS setup

    Navigate to the file ios/Runner/AppDelegate.swift and replace the whole code with the following:


    import UIKit

    import Flutter

    import GoogleMaps

     

    @UIApplicationMain

    @objc class AppDelegate: FlutterAppDelegate {

    override func application(

    _ application: UIApplication,

    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?

    ) -> Bool {

    //Add your Google Maps API Key here

    GMSServices.provideAPIKey("YOUR KEY HERE")

    GeneratedPluginRegistrant.register(with: self)

    return super.application(application, didFinishLaunchingWithOptions: launchOptions)

    }

    }


    To get the location permission, add the following to the same file:

    <key>NSLocationWhenInUseUsageDescription</key>

    <string>This app needs access to location when open.</string>


    This completes the setup for both platforms in Flutter.



  8. Integrating the Google Maps Widget
  9. Now you are ready to add the Google Maps widget to your Flutter app.

    You can start with the following code:

    import 'package:flutter/material.dart';

     

    void main() {

    runApp(MyApp());

    }

     

    class MyApp extends StatelessWidget {

    @override

    Widget build(BuildContext context) {

    return MaterialApp(

    title: 'Flutter Maps',

    theme: ThemeData(

    primarySwatch: Colors.blue,

    ),

    home: MapView(),

    );

    }

    }

     

    class MapView extends StatefulWidget {

    @override

    _MapViewState createState() => _MapViewState();

    }

     

    class _MapViewState extends State<MapView> {

    @override

    Widget build(BuildContext context) {

    // Determining the screen width & height

    var height = MediaQuery.of(context).size.height;

    var width = MediaQuery.of(context).size.width;

     

    return Container(

    height: height,

    width: width,

    child: Scaffold(

    body: Stack(

    children: <Widget>[

    // TODO: Add Map View

    ],

    ),

    ),

    );

    }

    }



    I have defined the Container height and width to be the size of the screen so that the Google Maps widget takes up the entire screen.

    I am also using a Stack to keep Google Maps widget in the background and add other necessary widgets on top of it.

    Now replace the TODO in the above code snippet with the Google Maps widget.


    // Import the Google Maps package

    import 'package:google_maps_flutter/google_maps_flutter.dart';

     

    // Initial location of the Map view

    CameraPosition _initialLocation = CameraPosition(target: LatLng(0.0, 0.0));

     

    // For controlling the view of the Map

    late GoogleMapController mapController;

     

    // Replace the "TODO" with this widget

    GoogleMap(

    initialCameraPosition: _initialLocation,

    myLocationEnabled: true,

    myLocationButtonEnabled: false,

    mapType: MapType.normal,

    zoomGesturesEnabled: true,

    zoomControlsEnabled: false,

    onMapCreated: (GoogleMapController controller) {

    mapController = controller;

    },

    ),


    Let’s take a look at the parameters defined in the Google Maps widget:

    • initialCameraPosition : This is a required parameter that is used for loading the map view on initial start-up.

    • myLocationEnabled: For showing your current location on the map with a blue dot.

    • myLocationButtonEnabled: This button is used to bring the user location to the center of the camera view.

    • mapType: For specifying the displayed map type (normal, satellite, hybrid or terrain).

    • zoomGesturesEnabled: Whether the map view should respond to zoom gestures.

    • zoomControlsEnabled: Whether to show zoom controls (only applicable for Android).

    • onMapCreated: Callback for when the map is ready to use.


    I have set the myLocationButtonEnabled and zoomControlsEnabled parameters as false because I am going to show you how to define a custom button with the same functionality but with better control.

    mapController would be used to control the camera position of the map view.

    By now, the app looks like this:


    To display the zoom buttons and the current location button you can add them as children to the Stack widget and position them accordingly.

    The code for designing a button is given below:


    // Design for current location button
     
    ClipOval(
      child: Material(
        color: Colors.orange.shade100, // button color
        child: InkWell(
          splashColor: Colors.orange, // inkwell color
          child: SizedBox(
            width: 56,
            height: 56,
            child: Icon(Icons.my_location),
          ),
          onTap: () {
            // TODO: Add the operation to be performed
            // on button tap
          },
        ),
      ),
    ),



    Using zoom in the map view

    You can use the mapController to zoom in and out on a map.


    // Zoom In action

    mapController.animateCamera(

    CameraUpdate.zoomIn(),

    );

     

    // Zoom Out action

    mapController.animateCamera(

    CameraUpdate.zoomOut(),

    );



    Move to a new position

    You can use the following code snippet to move to a new position:

    // Move camera to the specified latitude & longitude
    mapController.animateCamera(
      CameraUpdate.newCameraPosition(
        CameraPosition(
          target: LatLng(
            // Will be fetching in the next step
            _currentPosition.latitude,
            _currentPosition.longitude,
          ),
          zoom: 18.0,
        ),
      ),
    );


    Here, I have only specified the target and zoom properties of the CameraPosition widget. There are two more properties, bearing and tilt that you can use in a similar manner.

    In the target property, you have to pass the latitude and longitude of the position you want to move.

    Here, we need the Current Location button to move the camera view to the user’s present location. Let’s see how to achieve that.

    After adding the buttons, the app will look like this:



  10. Fetching current location
  11. There is a nice plugin for Flutter called Geolocator that can help you fetch the user’s current location.

    Add it to your pubspec.yaml file:

    geolocator: ^7.0.3

    Now let’s get started and go through it step-by-step.

    1. Define a variable to store the retrieved current location:

    2. // For storing the current position
      Position _currentPosition;


    3. Get the current location of the user:


    4. // Method for retrieving the current location
         
      _getCurrentLocation() async {
        await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high)
            .then((Position position) async {
          setState(() {
            // Store the position in the variable
            _currentPosition = position;
       
            print('CURRENT POS: $_currentPosition');
       
            // For moving the camera to current location
            mapController.animateCamera(
              CameraUpdate.newCameraPosition(
                CameraPosition(
                  target: LatLng(position.latitude, position.longitude),
                  zoom: 18.0,
                ),
              ),
            );
          });
          await _getAddress();
        }).catchError((e) {
          print(e);
        });
      }

    5. Add this method to the initState to fetch the user’s current location as soon as the app launches, and to move the camera to the detected location

    6. @override
      void initState() {
        super.initState();
        _getCurrentLocation();
      }

    7. Also pass the latitude and longitude to the onTap method of the custom button for fetching the current location.

    After completing these, the camera will automatically move to the detected location as the app launches.


  12. Placing Markers
  13. You can use the coordinates retrieved in the previous step to place markers on the map.

    • First of all, define a variable for storing the markers:

    • §  Set<Marker> markers = {};



    • Create the markers:

    • String startCoordinatesString = '($startLatitude, $startLongitude)';

      String destinationCoordinatesString = '($destinationLatitude, $destinationLongitude)';

       

      // Start Location Marker

      Marker startMarker = Marker(

      markerId: MarkerId(startCoordinatesString),

      position: LatLng(startLatitude, startLongitude),

      infoWindow: InfoWindow(

      title: 'Start $startCoordinatesString',

      snippet: _startAddress,

      ),

      icon: BitmapDescriptor.defaultMarker,

      );

       

      // Destination Location Marker

      Marker destinationMarker = Marker(

      markerId: MarkerId(destinationCoordinatesString),

      position: LatLng(destinationLatitude, destinationLongitude),

      infoWindow: InfoWindow(

      title: 'Destination $destinationCoordinatesString',

      snippet: _destinationAddress,

      ),

      icon: BitmapDescriptor.defaultMarker,

      );



    • Add the markers:

    • // Add the markers to the list

      markers.add(startMarker);

      markers.add(destinationMarker);



    • Display the markers on the map:

    • // Add the markers property to the widget

      GoogleMap(

      markers: Set<Marker>.from(markers),

      // ...

      ),



      If you run the app now, it will look like this:

      You will notice that only one of the markers is visible, although you placed two of them, one at the starting point and the other at the destination.

      So what’s happening here?

      Actually, both markers are added to the map, but only one of them is visible because the other one is out of the view. If you zoom out a bit, you will notice the other one too.

      You can use the following code snippet to reorient the map view to accommodate both markers.


      // Calculating to check that the position relative

      // to the frame, and pan & zoom the camera accordingly.

      double miny = (startLatitude <= destinationLatitude)

      ? startLatitude

      : destinationLatitude;

      double minx = (startLongitude <= destinationLongitude)

      ? startLongitude

      : destinationLongitude;

      double maxy = (startLatitude <= destinationLatitude)

      ? destinationLatitude

      : startLatitude;

      double maxx = (startLongitude <= destinationLongitude)

      ? destinationLongitude

      : startLongitude;

       

      double southWestLatitude = miny;

      double southWestLongitude = minx;

       

      double northEastLatitude = maxy;

      double northEastLongitude = maxx;

       

      // Accommodate the two locations within the

      // camera view of the map

      mapController.animateCamera(

      CameraUpdate.newLatLngBounds(

      LatLngBounds(

      northeast: LatLng(northEastLatitude, northEastLongitude),

      southwest: LatLng(southWestLatitude, southWestLongitude),

      ),

      100.0,

      ),

      );




For More :

  • Use Geocoding to translate coordinates into a place address and vice versa

  • Draw a route

  • Use Polylines for drawing route between two places

  • Calculate distance of that route

Source : Medium