Flutter - How can draw route on google map between two locations?

Hello guys today we are going to learn how to draw route path between two locations on Google Maps.
If you don't know how to load GoogleMap read my previous post

 

To achieve this we need to add below dependencies to pubspec.yaml file

GoogleMaps:
Load the Google Maps on to the screen
 
Provider:
To manage the State
 
GeoLocator:
To Fetch the Address from the Position

Google Webservices:
To Fetch the Route

 

Follow These steps 

Step 1: Create AppState Class & Put ChangeProvider in Main File

appstate.dart

class AppState extends ChangeNotifier{
 
 }

main.dart

void main() {
   runApp(
      MultiProvider(providers: [
        ChangeNotifierProvider.value(value: AppState())
      ],
        child: MyApp(),)
  );
}
class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(

        primarySwatch: Colors.blue,
      ),
      home: LandingPage(),
    );
  }
}

 

Step 2: Design the UI with Text Fields and Maps

landingpage.dart

class LandingPage extends StatefulWidget{
  @override
  State createState() =>LandingPageState();

}

class LandingPageState extends State
{
  @override
  Widget build(BuildContext context) {
    final appState=Provider.of(context);
    return SafeArea(
        child: appState.initialPosition==null?Container(
          child: Center(
            child: CircularProgressIndicator(),
          ),
        ):Stack(
          children: [
            GoogleMap(
                initialCameraPosition: CameraPosition(target: appState.initialPosition,zoom: 11),
                onMapCreated: appState.onCreated,
                onCameraMove: appState.onCameraMove,
              markers: appState.markers,
              polylines: appState.polyLines,
            ),
            Positioned(
              top: 50.0,
              right: 15.0,
              left: 15.0,

              child: Material(
                child: Container(
                  height: 50.0,
                  width: double.infinity,
                  decoration: getBoxShadow(),
                  child: TextField(
                    controller: appState.sourceController,
                    textInputAction: TextInputAction.next,
                    cursorColor: Colors.black,
                    decoration:getInoutDecoration("pick up Location?",Icon(
                      Icons.location_on,
                      color: Colors.green,
                    ),),
                  ),
                ),
              ),
            ),
            Positioned(
              top: 105.0,
              right: 15.0,
              left: 15.0,
              child: Material(
                child: Container(
                  height: 50.0,
                  width: double.infinity,
                  decoration:getBoxShadow(),
                  child: TextField(
                    controller: appState.destController,
                    cursorColor: Colors.black,
                    textInputAction: TextInputAction.go,
                    onSubmitted: (value) {
                     
                    },
                    decoration: getInoutDecoration("destination?",Icon(
                      Icons.local_taxi,
                      color: Colors.black,
                    )),
                  ),
                ),
              ),
            ),
            (appState.isLoading)?Center(child: CircularProgressIndicator(),):Container(width: 0,height: 0,),
          ],
        )

    );
  }

  getInoutDecoration(hint,icon)
  {
    return InputDecoration(
      icon: Container(
        margin: EdgeInsets.only(left: 20, top: 5),
        width: 10,
        height: 10,
        child:icon ,
      ),
      hintText: hint,
      border: InputBorder.none,
      contentPadding: EdgeInsets.only(left: 15.0, top: 16.0),
    );
  }
  getBoxShadow()
  {
    return BoxDecoration(
        borderRadius: BorderRadius.circular(3.0),
        color: Colors.white,
        boxShadow: [
          BoxShadow(
              color: Colors.grey,
              offset: Offset(1.0, 5.0),
              blurRadius: 10,
              spreadRadius: 3)
        ]);

  }
}

To Handle state changes we need to create AppState instance here


final appState=Provider.of(context);


This will handle the Entire app changes and update the state based on values.
I have updated the AppState class like below

Step 3: Write Logic to Fetch the Address and get Ploy Lines between Locations

import 'package:flutter/material.dart';

import 'package:geolocator/geolocator.dart';

import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:maps_uber_clone_app/module/pathrequest.dart';
class AppState extends ChangeNotifier{
  static LatLng _initialPosition;
  static LatLng _lastPosition;
  GoogleMapController _mapController;
  Set_markers={};
  Set  _polyLines={};
  bool _isLoading=false;

  //To Handle Text fileds data
  TextEditingController sourceController=TextEditingController();
  TextEditingController destController=TextEditingController();

  //To Get the Marker Psotions
  LatLng get initialPosition => _initialPosition;
  LatLng get lastposition => _lastPosition;
  
  //To check the Route Fetching stage
  bool get isLoading => _isLoading;

  GoogleMapController get mapController => _mapController;
  
  //TO Load Marjers on to Map
  Set get markers => _markers;
  
  //To Load route on Map
  Set get polyLines => _polyLines;

  Locationpath _locationPath = Locationpath();
  AppState()
  {
    _getUserLocation();
  }
  //  ON CREATE, Will set the MapController after loading the Map
  void onCreated(GoogleMapController controller) {
    _mapController = controller;
    notifyListeners();
  }

  // Handle the CameraMove Position
  void onCameraMove(CameraPosition position) {
    _lastPosition = position.target;
    notifyListeners();
  }

// Fetch the User Current location
  void _getUserLocation() async {
  
    Position position = await Geolocator()
        .getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
    List placemark = await Geolocator()
        .placemarkFromCoordinates(position.latitude, position.longitude);
    _initialPosition = LatLng(position.latitude, position.longitude);
    
    sourceController.text = placemark[0].name;
    _markers.add(Marker(markerId: MarkerId(position.toString()),icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueOrange),position: LatLng(position.latitude, position.longitude)));
    notifyListeners();
  }

  // To Request Route path to Goolge Webservice 
  void sendRequest(String intendedLocation) async {
    _isLoading=true;
    List placemark =
    await Geolocator().placemarkFromAddress(intendedLocation);
    double latitude = placemark[0].position.latitude;
    double longitude = placemark[0].position.longitude;
    LatLng destination = LatLng(latitude, longitude);
    _addMarker(destination, intendedLocation);
    String route = await _locationPath.getRouteCoordinates(
        _initialPosition, destination);
    createRoute(route);
    notifyListeners();
  }

  // Add marker to markers set and update Map on Marker
  void _addMarker(LatLng location, String address) {
    _markers.add(Marker(
        markerId: MarkerId(_lastPosition.toString()),
        position: location,
        infoWindow: InfoWindow(title: address, snippet: "Destination"),
        icon: BitmapDescriptor.defaultMarker));
    notifyListeners();
  }
// ! TO CREATE ROUTE
  void createRoute(String encondedPoly) {
    _polyLines.add(Polyline(
        polylineId: PolylineId(_lastPosition.toString()),
        width: 4,
        points: _convertToLatLng(_decodePoly(encondedPoly)),
        color: Colors.deepPurple));
    _isLoading=false;
    notifyListeners();
  }
 
  List _convertToLatLng(List points) {
    List result = [];
    for (int i = 0; i < points.length; i++) {
      if (i % 2 != 0) {
        result.add(LatLng(points[i - 1], points[i]));
      }
    }
    return result;
  }
  // DECODE POLY
  List _decodePoly(String poly) {
    var list = poly.codeUnits;
    var lList = new List();
    int index = 0;
    int len = poly.length;
    int c = 0;

    do {
      var shift = 0;
      int result = 0;

     
      do {
        c = list[index] - 63;
        result |= (c & 0x1F) << (shift * 5);
        index++;
        shift++;
      } while (c >= 32);
     
      if (result & 1 == 1) {
        result = ~result;
      }
      var result1 = (result >> 1) * 0.00001;
      lList.add(result1);
    } while (index < len);

/*adding to previous value as done in encoding */
    for (var i = 2; i < lList.length; i++) lList[i] += lList[i - 2];

    print(lList.toString());

    return lList;
  }
}

locationpath.dart

import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
const apiKey = "PUT_YOUR_KEY";
class Locationpath {
  Future getRouteCoordinates(LatLng l1, LatLng l2)async{
    String url = "https://maps.googleapis.com/maps/api/directions/json?origin=${l1.latitude},${l1.longitude}&destination=${l2.latitude}, ${l2.longitude}&key=$apiKey";
    http.Response response = await http.get(url);
    Map values = jsonDecode(response.body);
    return values["routes"][0]["overview_polyline"]["points"];
  }
}

 

Run App, The Current location will be show in Source Text Field, then enter Destination address in Destination Text Field and hit keyboard go button, it will fetch the Route path and display the Route between two markers.




Related Questions View All