Introduction
In this Flutter application, we aim to create a user-friendly tool that allows users to track their movements and calculate the distance covered using latitude and longitude coordinates. The app employs the geolocator
package for location services and includes features such as continuous location tracking, real-time distance updates, and the ability to export location data to an Excel file.
Getting Started
Let's start by setting up a basic Flutter project. Ensure you have Flutter and Dart installed on your machine. Create a new Flutter project using the following command:
flutter create distance_tracker
Navigate to the project directory:
cd distance_tracker
Now, replace the contents of the lib/main.dart
file with the provided code. This code sets up the basic structure of a Flutter app and includes the necessary dependencies for geolocation.
Dependencies
Our app relies on the geolocator
package to access the device's location services. To include this package, open your pubspec.yaml
file and add the following dependency:
dependencies:
flutter:
sdk:
flutter
geolocator: ^7.9.1
Don't forget to run:
flutter pub get
App Structure
Main App Widget
The MyApp
widget is the main entry point of our application. It sets up the theme and defines the home screen as an instance of the Home
widget.
Home Widget
The Home
widget is a stateful widget representing the main screen of our app. It includes a Google Map controller, markers for the map, and polylines to visualize the traveled path.
class MyApp extends StatelessWidget { const MyApp({super.key});
// This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'Flutter Demo', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), home: Home(), ); }}
Location Tracking
The determinePosition
method checks and requests location permissions. It subscribes to the device's location stream and continuously updates the user's location. The locationCheck
method calculates the distance traveled using the Haversine formula.
Full Source Code :
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:flutter_polyline_points/flutter_polyline_points.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: Home(),
);
}
}
class Home extends StatefulWidget {
Home({Key? key}) : super(key: key);
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
double distance = 0.0;
double latnew = 0.0;
double longnew = 0.0;
@override
void initState() {
setState(() {
determinePosition();
});
super.initState();
}
int distanse2 = 0;
Future<void> determinePosition() async {
bool serviceEnabled;
LocationPermission permission;
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
// log("Location permission true"+permission.toString());
Geolocator.openLocationSettings();
} else {
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {}
}
if (permission == LocationPermission.deniedForever) {
// Geolocator.openAppSettings();
} else {
await locationCheck();
}
if (permission == LocationPermission.always ||
permission == LocationPermission.whileInUse) {
await locationCheck();
}
}
}
List<latlongdetails> data = [];
double totalDistance = 0;
Future<void> locationCheck() async {
StreamSubscription<Position> positionStream = Geolocator.getPositionStream(
locationSettings: LocationSettings(
distanceFilter: distanse2,
accuracy: LocationAccuracy.best,
)).listen((Position? position) async {
setState(() {
double oldlat = 0.00;
double oldlong = 0.00;
latnew = position!.latitude;
longnew = position.longitude;
print('lat::' + latnew.toString());
print('long::' + longnew.toString());
if (startLatitude != 0.00 && startLongtitue != 0.00) {
data.add(latlongdetails(
lat: latnew, long: longnew, totaldistance: totalDistance));
if (data.length == 1) {
oldlat = latnew;
oldlong = longnew;
// if (data[data.length].lat != oldlat &&
// data[data.length].long != oldlong) {
// totalDistance += calculateDistance(oldlat, oldlong,
// data[data.length].lat, data[data.length].long);
// }
} else {
oldlat = data[data.length - 2].lat;
oldlong = data[data.length - 2].long;
totalDistance +=
calculateDistance(oldlat, oldlong, latnew, longnew);
}
// for (var i = 0; i < data.length - 1; i++) {
// totalDistance += calculateDistance(
// data[i].lat, data[i].long, data[i + 1].lat, data[i + 1].long);
// }
print('distance:::' + totalDistance.toString());
}
setState(() {
distance = totalDistance;
});
});
});
}
double? startLatitude = 0.00;
double? startLongtitue = 0.00;
getLocation() async {
Position position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.best);
setState(() {
startLatitude = position.latitude;
startLongtitue = position.longitude;
});
}
double calculateDistance(lat1, lon1, lat2, lon2) {
print('process lat' + lat1.toString());
print('process long' + lon1.toString());
var p = 0.017453292519943295;
var a = 0.5 -
cos((lat2 - lat1) * p) / 2 +
cos(lat1 * p) * cos(lat2 * p) * (1 - cos((lon2 - lon1) * p)) / 2;
return 12742 * asin(sqrt(a));
}
clearall() {
setState(() {
data.clear();
latnew = 0.00;
longnew = 0.00;
distance = 0.0;
startLatitude = 0.00;
startLongtitue = 0.00;
totalDistance = 0;
});
}
setstring2(String temp) {
setState(() {
if (temp.isNotEmpty) {
distanse2 = int.parse(temp.toString());
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Calculate Distance"),
backgroundColor: Colors.deepPurpleAccent,
),
body: Container(
width: double.infinity,
height: double.infinity,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
alignment: Alignment.center,
color: Colors.grey[200],
width: 400,
height: 50,
child: Text(
'Start Point:${startLatitude} , ${startLongtitue}'),
),
Container(
alignment: Alignment.center,
color: Colors.grey[200],
width: 400,
height: 50,
child: Text('Live:${latnew} , ${longnew}'),
),
Container(
child: Card(
child: Container(
padding: EdgeInsets.all(20),
child: Text(
"Total Distance: " +
distance.toString() +
" KM \n Dis.Met:${distanse2}",
style: TextStyle(
fontSize: 20, fontWeight: FontWeight.bold))),
)),
SizedBox(
height: 100,
),
Container(
width: 300,
child: TextFormField(
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(
vertical: 10.0, horizontal: 10.0),
fillColor: Colors.grey[200],
filled: true,
labelText: "Distant Value",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: const BorderSide(
color: Colors.lightBlueAccent,
),
),
),
onChanged: (value) {
setState(() {
setstring2(value);
});
},
),
),
ElevatedButton(
onPressed: () {
setState(() {
clearall();
getLocation();
});
},
child: Text('Start Track')),
ElevatedButton(
onPressed: () {
setState(() {
clearall();
determinePosition();
});
},
child: Text('Clear All')),
//exportexcel()
]),
),
));
}
}
class latlongdetails {
dynamic lat;
dynamic long;
double totaldistance;
latlongdetails(
{required this.lat, required this.long, required this.totaldistance});
}
App:
User Interface
The UI includes components to display the starting point, live location, and total distance covered. Users can input a distance filter, start tracking their movement, and export tracked data to an Excel file.
Running the App
Before running the app, ensure your device's location services are enabled. Run the app using
flutter
run
Conclusion
In this tutorial, we've built a Flutter app that calculates and tracks the distance based on real-time location updates. This app can serve as a foundation for more advanced features, such as map integration, data visualization, and offline mode.
Feel free to enhance the app further, add new features, and adapt it to your specific use case. Happy coding!