Flutter Farm Mapping App With Google Maps Integration
In this tutorial, we will create a Flutter application for farm mapping with Google Maps integration.
Flutter Farm Mapping App with Google Maps Integration
The app enables users to draw and save geofenced areas on a map, each represented by a different color.
flutter farm app tutorial ad
Prerequisites
Flutter SDK installed on your machine.
An IDE such as Visual Studio Code or Android Studio.
A Google Cloud Platform (GCP) account to obtain a Google Maps API Key.
Step 1: Create A New Flutter Project
Open your terminal and run the following commands:
bashCopy code
flutter create geo_farm
cd geo_farm
Step 2: Add Dependencies
Open the pubspec.yaml
file and add the necessary dependencies:
/Pubspec.yaml
dependencies: flutter:
sdk:
flutter cupertino_icons: ^1.0.2
google_maps_flutter: ^2.5.3
geolocator: ^10.1.0
flutter_colorpicker: ^1.0.3
shared_preferences: ^2.2.2
flutter_polyline_points: ^2.0.0
hive: ^2.2.3
hive_flutter: ^1.1.0
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0
hive_generator: ^2.0.0
build_runner:
Run flutter pub get
in the terminal to fetch the dependencies.
Step 3: Google Maps API Key
Go to the Google Cloud Console.
Create a new project or select an existing one.
Enable the “Maps SDK for Android” and “Maps SDK for iOS” APIs.
Create an API Key in the “Credentials” section.
Restrict the API Key for Android and iOS apps by specifying package names and SHA-1/SHA-256 fingerprints (OPTIONAL).
Copy the generated API Key.
Step 4: Configure Android And IOS
Android Configuration
Open android/app/build.gradle
and update the defaultConfig
block:
/android/app/build.gradle
android {
... defaultConfig
{ ...
minSdkVersion 23
targetSdkVersion flutter.targetSdkVersion ...
} }
Open android/app/src/main/AndroidManifest.xml
and add the required permissions and API Key:
android/app/src/main/AndroidManifest.xml
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.geo_farming">
<uses-permissionandroid:name="android.permission.INTERNET"/>
<uses-permissionandroid:name="android.permission.ACCESS_FINE_LOCATION"/>
<application>
...
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="YOUR_API_KEY"/>
...
</application> </manifest>
IOS Configuration
Open ios/Runner/AppDelegate.swift
and add the following code:
ios/Runner/AppDelegate.swift
import UIKit
import Flutter
import GoogleMaps
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { GMSServices.provideAPIKey("YOUR_API_KEY")
GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
Open ios/Runner/Info.plist
and add the following:
ios/Runner/Info.plist
<key>NSLocationWhenInUseUsageDescription</key>
<string>We need your location for...</string>
<key>io.flutter.embedded_views_preview</key>
<string>YES</string>
Replace YOUR_ANDROID_API_KEY
and YOUR_IOS_API_KEY
with the API keys obtained from the Google Cloud Console.
Step 5: Implement The Main Dart File
Open lib/main.dart
and replace the existing code with the following:
lib/main.dart
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'models/field.dart';
void main() async {
await Hive.initFlutter(); Hive.registerAdapter(FieldAdapter());
await Hive.openBox<Field>('fields');
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override Widget build(BuildContext context) {
return MaterialApp( home: MyFarmMap(),
);
}
}
Step 6: Create The Model
Create a new file lib/models/field.dart
and add the following code:
lib/models/field.dart
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:hive/hive.dart';
part 'field.g.dart';
@HiveType(typeId: 0)
class Field extends HiveObject {
@HiveField(0)
final String id;
@HiveField(1)
final String color;
@HiveField(2)
final String label;
@HiveField(3)
final List<LatLng> borderCoordinates;
Field({ required this.id, required this.color, required this.label, required this.borderCoordinates, });
Map<String, dynamic> toJson() {
return {
'id': id,
'color': color,
'label': label,
'borderCoordinates': borderCoordinates.map((latLng) => {'latitude': latLng.latitude, 'longitude': latLng.longitude}).toList(),
};
}
factory Field.fromJson(Map<String, dynamic> json) {
return Field(
id: json['id'],
color: json['color'],
label: json['label'],
borderCoordinates: (json['borderCoordinates'] as List<dynamic>).map((coords) => LatLng(coords['latitude'], coords['longitude'])).toList(), );
}
}
Step 6.1: Run Build Runner
After creating the field.dart
model, you need to run the build runner command to generate the necessary code for Hive.
Open your terminal, navigate to the project directory, and run:
flutter pub run build_runner build
This command triggers code generation for Hive adapters. It’s essential to execute this command whenever you make changes to your model classes annotated with Hive annotations (@HiveType
, @HiveField
).
Step 7: Implement The Main Map Widget
Open lib/main.dart
and add the following code for the MyFarmMap
widget:
lib/main.dart
class MyFarmMap extends StatefulWidget {
@override _MyFarmMapState createState() => _MyFarmMapState(); }
class _MyFarmMapState extends State<MyFarmMap> {
GoogleMapController? mapController;
List<Field> fields = [];
List<LatLng> currentPolyline = [];
Color currentPolylineColor = Colors.red;
void _saveFields() async {
final box = Hive.box<Field>('fields');
await box.clear();
// Clear previous fields
await box.addAll(fields);
}
@override void initState() {
super.initState();
_loadFields();
// Load saved fields when the app starts
}
Future<void> _loadFields() async {
final box = Hive.box<Field>('fields');
setState(() {
fields = box.values.toList();
}); }
@override Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Farm Map')),
body: GoogleMap(
onMapCreated: (controller) {
mapController = controller;
},
initialCameraPosition: CameraPosition( target: LatLng(-34.0425, 22.2313889),
zoom: 13.0, ),
onTap: _handleMapTap,
polylines: _getPolylines(),
mapType: MapType.satellite,
markers: _getMarkers(),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
FloatingActionButton( onPressed: () => _showColorPicker(),
child: Icon(Icons.color_lens),
),
SizedBox(height: 16),
FloatingActionButton( onPressed: () => _toggleMapType(),
child: Icon(Icons.map),
),
SizedBox(height: 16), FloatingActionButton( onPressed: () => _handleMapLongPress(),
child: Icon(Icons.add),
),
],
),
);
}
Set<Polyline> _getPolylines() {
Set<Polyline> polylines = fields.map((field) {
return Polyline(
polylineId: PolylineId(field.id),
points: field.borderCoordinates,
color: Color(int.parse(field.color)),
width: 2,
);
}).toSet();
if (currentPolyline.isNotEmpty) {
polylines.add( Polyline(
polylineId: PolylineId('currentPolyline'),
points: currentPolyline,
color: currentPolylineColor,
width: 2,
),
);
}
return polylines;
}
Set<Marker> _getMarkers() {
return fields.map((field) {
return Marker(
markerId: MarkerId(field.id),
position: field.borderCoordinates[0], // You can adjust this to position the label marker
infoWindow: InfoWindow(
title: field.label,
snippet: 'Geofenced Area',
),
);
}).toSet();
}
void _toggleMapType() {
setState(() { // Toggle between normal and satellite map types //
mapController!.animateCamera(CameraUpdate.newLatLng(mapController!.cameraPosition.target)); });
}
void _handleMapTap(LatLng latLng) {
setState(() {
currentPolyline.add(latLng);
});
}
void _handleMapLongPress() {
if (currentPolyline.isNotEmpty) {
showDialog( context: context, builder: (BuildContext context) {
return AlertDialog(
title: Text('Enter Name for Geofenced Area:'),
content: TextField( onChanged: (value) { // You can handle the entered name here },
),
actions: <Widget>[
TextButton( onPressed: () {
Navigator.of(context).pop();
},
child: Text('Cancel'),
),
TextButton( onPressed: () {
setState(() {
fields.add(Field(
id: UniqueKey().toString(),
label: 'Field ${fields.length + 1}',
color: currentPolylineColor.value.toString(),
borderCoordinates: List.from(currentPolyline),
));
currentPolyline.clear();
_saveFields();
});
Navigator.of(context).pop();
},
child: Text('OK'),
),
],
);
},
);
}
}
void _showColorPicker() {
showDialog(
context: context, builder: (BuildContext context) {
return AlertDialog(
title: const Text('Pick a color'),
content: SingleChildScrollView( child:
ColorPicker(
pickerColor: currentPolylineColor,
onColorChanged: (Color color) { setState(() => currentPolylineColor = color); },
showLabel: true,
pickerAreaHeightPercent: 0.8,
),
),
actions: <Widget>[
TextButton( onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Cancel'),
),
TextButton( onPressed: () {
setState(() {
_handleMapLongPress();
});
Navigator.of(context).pop();
},
child: const Text('OK'),
),
],
);
},
);
}
}
This completes the implementation of the Flutter Farm Mapping App with Google Maps integration. Run your app using flutter run
in the terminal and see your farm map in action!
Feel free to customize and enhance the app based on your specific requirements. Happy coding!
Full Code : https://github.com/iDigiSolWeb
Visit iDigiSolWeb.com if you require app development services
Subscribe to my newsletter
Read articles from iDigiSol Web directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
iDigiSol Web
iDigiSol Web
iDigiSol Web is a dynamic and forward-thinking app development and e-commerce consulting company dedicated to helping businesses thrive in the digital landscape. With a team of seasoned experts and creative minds, we specialize in crafting cutting-edge mobile applications and providing strategic guidance to e-commerce ventures, ensuring they reach their fullest potential in the online marketplace.