Flutter Google Map With Live Location Tracking — Uber Style

The Flutter Way
Flutter Community
Published in
6 min readJun 21, 2022

--

With this lesson, you will learn how to use Google Maps in Flutter with some customizations, like setting up Custom Image Markers and drawing route direction polylines. Add real-time location updates to the map.

Google Map Live tracking preview

Table of content ::

Initial Setup ⚙️

Google Map 🗺

Draw Route Direction 〰

Real-time Location Updates on Map 🔴

Add custom marker/pin 📍

Video Tutorial 🎬

Complete Source code 🔥

Note: This post assumes you already have the maps set up in your project using the Google Maps Flutter Package and your own Google Maps API key. If not, follow this link on how to set up your Flutter project to work with Google Maps. Other dependencies include the Flutter Polyline Points package and the Flutter Location Plugin.

Initial Setup ⚙️

Make sure you prep your environment accordingly to enable location tracking on both IOS and Android by following the steps in the package’s README regarding the Android manifest file and the iOS Info.plist.

Once set up, the dependences look like 👇

....
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
flutter_polyline_points: ^1.0.0
google_maps_flutter: ^2.1.7
location: ^4.4.0
...

Note: As of this writing, the versions of the packages above were the ones available — please update accordingly.

Google Map 🗺

Create a StatefulWidget called OrderTrackingPage with its corresponding State class, where I imported the required packages as well as some hardcoded source and destination location (for the sake of this tutorial).

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
class OrderTrackingPage extends StatefulWidget {
const OrderTrackingPage({Key? key}) : super(key: key);
@override
State<OrderTrackingPage> createState() => OrderTrackingPageState();
}
class OrderTrackingPageState extends State<OrderTrackingPage> {
final Completer<GoogleMapController> _controller = Completer();
static const LatLng sourceLocation = LatLng(37.33500926, -122.03272188);
static const LatLng destination = LatLng(37.33429383, -122.06600055);
@override
Widget build(BuildContext context) {
return Scaffold(
body: ... GoogleMap widget will be here ...,
);
}
}

Create the GoogleMap widget and set the initialCameraPosition to the location of the source. The map needs to be zoomed in a bit, so set it to 13.5.

We need a marker/pin to understand the exact location. Define a marker and set its position to the source location. For the destination, add another marker/pin.

GoogleMap(
initialCameraPosition: const CameraPosition(
target: sourceLocation,
zoom: 13.5,
),
markers: {
const Marker(
markerId: MarkerId("source"),
position: sourceLocation,
),
const Marker(
markerId: MarkerId("destination"),
position: destination,
),
},
onMapCreated: (mapController) {
_controller.complete(mapController);
},
),
Map preview with marker/pin

Draw Route Direction 〰

The next thing I want to do is draw a line from destination to source. Create an empty list called polylineCoordinates. Create an instance of PolylinePoints and an async function called getPolyPoints. The method getRouteBetweenCoordinates returns the list of polyline points. The Google API key, source, and destination locations were required. If the points are not empty, we store them to polylineCoordinates.

List<LatLng> polylineCoordinates = [];void getPolyPoints() async {
PolylinePoints polylinePoints = PolylinePoints();
PolylineResult result = await polylinePoints.getRouteBetweenCoordinates(
google_api_key, // Your Google Map Key
PointLatLng(sourceLocation.latitude, sourceLocation.longitude),
PointLatLng(destination.latitude, destination.longitude),
);
if (result.points.isNotEmpty) {
result.points.forEach(
(PointLatLng point) => polylineCoordinates.add(
LatLng(point.latitude, point.longitude),
),
);
setState(() {});
}
}

On initState call getPolyPoints

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

Back to the GoogleMap widget, define the polylines.

GoogleMap(...  polylines: {
Polyline(
polylineId: const PolylineId("route"),
points: polylineCoordinates,
color: const Color(0xFF7B61FF),
width: 6,
),
},
),
Map with route

Real-time Location Updates on Map 🔴

Now come to the most exciting part, we need the device’s location. Create a nullable variable called currentLocation. Then a function called getCurrentLocation, Inside, creates an instance of Location. Once we get the location, set the current location to be equal to the location. On location change, update the current location. Make it visible to the map called setState.

LocationData? currentLocation;void getCurrentLocation() async {
Location location = Location();
location.getLocation().then(
(location) {
currentLocation = location;
},
);
GoogleMapController googleMapController = await _controller.future;location.onLocationChanged.listen(
(newLoc) {
currentLocation = newLoc;
googleMapController.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(
zoom: 13.5,
target: LatLng(
newLoc.latitude!,
newLoc.longitude!,
),
),
),
);
setState(() {});
},
);
}

Make sure to call the getCurrentLocation on initState.

void initState() {
getPolyPoints();
getCurrentLocation();
super.initState();
}

If the currentLocation is null, it shows a loading text. Also, add another marker/pin for the currentLocation as well as change the initial camera position to the current location.

Complete body 👇

body: currentLocation == null
? const Center(child: Text("Loading"))
:
GoogleMap(
initialCameraPosition: CameraPosition(
target: LatLng(
currentLocation!.latitude!, currentLocation!.longitude!),

zoom: 13.5,
),
markers: {
Marker(
markerId: const MarkerId("currentLocation"),
position: LatLng(
currentLocation!.latitude!, currentLocation!.longitude!),
),

const Marker(
markerId: MarkerId("source"),
position: sourceLocation,
),
const Marker(
markerId: MarkerId("destination"),
position: destination,
),
},
onMapCreated: (mapController) {
_controller.complete(mapController);
},
polylines: {
Polyline(
polylineId: const PolylineId("route"),
points: polylineCoordinates,
color: const Color(0xFF7B61FF),
width: 6,
),
},
),
Live location tracking — 8X

Note: To simulate the location , you need to do some modifications.

For iOS ::

Go to Features, hover over location, select Freeway drive. I’m using source & destination location according to this Freeway drive.

iOS location simulate

For Android ::

If you are on Windows or using an Android simulator, click on the bottom three dots and ensure you are on location. Let’s say the source location is Google Plex, change the sourceLocation to this coordinate and the destination location is the Microsoft silicon valley campus. Change the destination with this location. Now click on the “routes” tab, and search for Microsoft silicon valley and Google plex for starting point. Save the route, set a playback speed hit play route. The current location is moving that’s what we want.

static const LatLng sourceLocation = your chosen locationstatic const LatLng destination = your chosen location

Add custom Marker/Pin 📍

The source, destination, and current location icons are the same. Let’s use a custom marker/pin for them.

BitmapDescriptor sourceIcon = BitmapDescriptor.defaultMarker;
BitmapDescriptor destinationIcon = BitmapDescriptor.defaultMarker;
BitmapDescriptor currentLocationIcon = BitmapDescriptor.defaultMarker;
void setCustomMarkerIcon() {
BitmapDescriptor.fromAssetImage(
ImageConfiguration.empty, "assets/Pin_source.png")
.then(
(icon) {
sourceIcon = icon;
},
);
BitmapDescriptor.fromAssetImage(
ImageConfiguration.empty, "assets/Pin_destination.png")
.then(
(icon) {
destinationIcon = icon;
},
);
BitmapDescriptor.fromAssetImage(
ImageConfiguration.empty, "assets/Badge.png")
.then(
(icon) {
currentLocationIcon = icon;
},
);
}

Call setCustomMarkerIcon on initState

void initState() {
getPolyPoints();
getCurrentLocation();
setCustomMarkerIcon();
super.initState();
}

The final touch, on the marker set icon.

GoogleMap(....    markers: {
Marker(
markerId: const MarkerId("currentLocation"),
icon: currentLocationIcon,
position: LatLng(
currentLocation!.latitude!, currentLocation!.longitude!),
),
Marker(
markerId: const MarkerId("source"),
icon: sourceIcon,
position: sourceLocation,
),
Marker(
markerId: MarkerId("destination"),
icon: destinationIcon,
position: destination,
),
},
),
Preview with custom marker/pin — 13x

Video tutorial 🎬

Complet source code 🔥

Bonus 🥳 Shop UI Kit

❤ ❤ Thanks for reading this article ❤❤

If I got something wrong? Let me know in the comments. I would love to improve.

Clap 👏 If this article helps you.

--

--

The Flutter Way
Flutter Community

Want to improve your flutter skill? Join our channel, learn how to become an expert flutter developer and land your next dream job!