Show Active Area in Flutter With Google Maps - Create a polygon hole

Ahmet Can Poyraz
6 min readOct 10, 2022

--

In this article, I will show that how to create polygon hole such as active area in Google Maps for Flutter. I explained simply about topic you can develop more with live location etc. So I hope it will be useful for you.

Preview of Active Area in Google Map

Note: You should 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.

Setup

We will need Flutter Toast and Google Maps Flutter packages. This article made for Google Maps but you can use another map plugins.

Add packages to dependencies in pubspec.yaml.


dependencies:
google_maps_flutter: ^2.2.0
fluttertoast: ^8.0.9

Let’s Code

First of all, we we define controller for Google Maps, polygons, markers and object of FlutterToast. Then call setMaker and setPolygon functions, I will explain what we are doing in this functions below later.

final Completer<GoogleMapController?> controller = Completer();
Set<Polygon> _polygons = HashSet<Polygon>();
List<Marker> _markers = <Marker>[];
late FToast fToast;
@override
void initState() {
super.initState();
fToast = FToast();
fToast.init(context);
setMarker();
setPolygon();

}

setPolygon();

void setPolygon(){
_polygons.add( Polygon(
fillColor: Colors.black.withOpacity(0.5),
polygonId: const PolygonId('polyId1'),
holes: const [
<LatLng>[
LatLng(38.394084, 26.967461),
LatLng(38.388164, 26.947205),
LatLng(38.383320, 26.934159),
LatLng(38.384262, 26.924718),
LatLng(38.378879, 26.923344),
LatLng(38.373092, 26.924203),
LatLng(38.365152, 26.931584),
LatLng(38.364479, 26.937421),
LatLng(38.362594, 26.948235),
LatLng(38.355595, 26.953557),
LatLng(38.357480, 26.970895),
LatLng(38.343344, 26.976216),
LatLng(38.334054, 27.002480),
LatLng(38.348864, 27.009690),
LatLng(38.362594, 27.015870),
LatLng(38.364479, 27.021191),
LatLng(38.378072, 27.019647),
LatLng(38.380494, 27.033551),
LatLng(38.386953, 27.033894),
LatLng(38.392873, 27.022908),
LatLng(38.406192, 27.021191),
LatLng(38.417625, 27.017415),
LatLng(38.408344, 27.009175),
LatLng(38.408209, 27.001965),
LatLng(38.405654, 26.994412),
LatLng(38.400138, 26.987889),
LatLng(38.395429, 26.973641),
]
],
points: const [
LatLng(-89, 0),
LatLng(89, 0),
LatLng(89, 179.999),
LatLng(-89, 179.999),
],
visible: true,
geodesic: false,
strokeWidth: 1,
consumeTapEvents: true,
onTap: (){
_showToast();
},
),
);

_polygons.add(
Polygon(
fillColor: Colors.black.withOpacity(0.5),
polygonId: const PolygonId('polyId2'),
points: const [
LatLng(-89.9, 0),
LatLng(89.9, 0),
LatLng(89.9, -179.999),
LatLng(-89.9, -179.999),
],
visible: true,
geodesic: false,
strokeWidth: 1,
),
);

_polygons.add(
Polygon(

fillColor: Colors.black.withOpacity(0.5),
polygonId: const PolygonId('polyId3'),
points: const [
LatLng(38.372554, 26.973985),
LatLng(38.364344, 26.974843),
LatLng(38.365286, 26.983426),
LatLng(38.371478, 26.982053),
],
onTap: (){
_showToast();
},
consumeTapEvents: true,
visible: true,
geodesic: false,
strokeWidth: 1,
),
);
}

Actually, this is the most impressive point. This function adding polygons and holes of polygons. I will explain in detail. While adding polygon with polyId1, we are adding holes coordinates this is our active area. Then we adding points with polyId1 and polyId2 polygons. This coordinates

LatLng(-89, 0),          and        LatLng(-89.9, 0),
LatLng(89, 0), LatLng(89.9, 0),
LatLng(89, 179.999), LatLng(89.9, -179.999),
LatLng(-89, 179.999), LatLng(-89.9, -179.999),

That points of polygons make all world passive area, and holes makes active area like below image.

polyId1 polygon’s holes showing like that

I think you understand so far, so how is the passive zone created in the active holes? Easly we are adding new polygon to _polygons like below code.

_polygons.add(
Polygon(

fillColor: Colors.black.withOpacity(0.5),
polygonId: const PolygonId('polyId3'),
points: const [
LatLng(38.372554, 26.973985),
LatLng(38.364344, 26.974843),
LatLng(38.365286, 26.983426),
LatLng(38.371478, 26.982053),
],
onTap: (){
_showToast();
},
consumeTapEvents: true,
visible: true,
geodesic: false,
strokeWidth: 1,
),
);
polyId3 Polygon

_showToast()

And we have _showToast function in onTap of Polygons. Toast seems in when we click passive area, that code is below

_showToast() {
// To clear the queue
fToast.removeQueuedCustomToasts();
Widget toast = Container(
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 12.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25.0),
color: Colors.redAccent,
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: const [
Icon(Icons.close,color: Colors.white,),
SizedBox(
width: 12.0,
),
Text("Outside Of Active Area",style: TextStyle(color: Colors.white),),
],
),
);
fToast.showToast(
child: toast,
gravity: ToastGravity.BOTTOM,
toastDuration: const Duration(seconds: 2),
);
}

setMarker()

We also had setMarker function in initState, in this function we adding markers to _markers list with onTap method. When we click markers showing infoWindow and and toast message disappear. So that’s code is below

void setMarker(){
_markers.add(
Marker(
markerId: MarkerId('markerId1'),
position: LatLng(38.391455, 27.018199),
infoWindow: InfoWindow(
title: 'Marker1'
),
onTap: (){
fToast.removeQueuedCustomToasts();
}
)
);
_markers.add(
Marker(
markerId: MarkerId('markerId2'),
position: LatLng(38.376015, 26.950806),
infoWindow: InfoWindow(
title: 'Marker2'
),
onTap: (){
fToast.removeQueuedCustomToasts();
}
)
);
}

build()

In build we have only GoogleMap, we define parameters, give controllers and onTap function.

@override
Widget build(BuildContext context) {
return Scaffold(
body: GoogleMap(
myLocationEnabled: true,
myLocationButtonEnabled: false,
zoomControlsEnabled: true,
initialCameraPosition: CameraPosition(
target: LatLng(38.397498, 27.040055),
zoom: 11),
onMapCreated: (mapController) {
if (controller.isCompleted) {
controller.complete(mapController);
}
},
onTap: (latlng){
fToast.removeQueuedCustomToasts();
},
polygons: _polygons,
markers: Set<Marker>.of(_markers),
));
}

All code is below

import 'dart:async';
import 'dart:collection';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';



class MapPage extends StatefulWidget {
const MapPage({Key? key}) : super(key: key);
@override
State<MapPage> createState() => _MapPageState();
}

class _MapPageState extends State<MapPage> {
final Completer<GoogleMapController?> controller = Completer();
Set<Polygon> _polygons = HashSet<Polygon>();
List<Marker> _markers = <Marker>[];
late FToast fToast;


@override
void initState() {
super.initState();
fToast = FToast();
fToast.init(context);
setMarker();
setPolygon();

}

@override
void dispose(){
super.dispose();
fToast.removeQueuedCustomToasts();
}


_showToast() {
// To clear the queue
fToast.removeQueuedCustomToasts();
Widget toast = Container(
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 12.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25.0),
color: Colors.redAccent,
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: const [
Icon(Icons.close,color: Colors.white,),
SizedBox(
width: 12.0,
),
Text("Outside Of Active Area",style: TextStyle(color: Colors.white),),
],
),
);
fToast.showToast(
child: toast,
gravity: ToastGravity.BOTTOM,
toastDuration: const Duration(seconds: 2),
);
}





void setPolygon(){
_polygons.add( Polygon(
fillColor: Colors.black.withOpacity(0.5),
polygonId: const PolygonId('polyId1'),
holes: const [
<LatLng>[
LatLng(38.394084, 26.967461),
LatLng(38.388164, 26.947205),
LatLng(38.383320, 26.934159),
LatLng(38.384262, 26.924718),
LatLng(38.378879, 26.923344),
LatLng(38.373092, 26.924203),
LatLng(38.365152, 26.931584),
LatLng(38.364479, 26.937421),
LatLng(38.362594, 26.948235),
LatLng(38.355595, 26.953557),
LatLng(38.357480, 26.970895),
LatLng(38.343344, 26.976216),
LatLng(38.334054, 27.002480),
LatLng(38.348864, 27.009690),
LatLng(38.362594, 27.015870),
LatLng(38.364479, 27.021191),
LatLng(38.378072, 27.019647),
LatLng(38.380494, 27.033551),
LatLng(38.386953, 27.033894),
LatLng(38.392873, 27.022908),
LatLng(38.406192, 27.021191),
LatLng(38.417625, 27.017415),
LatLng(38.408344, 27.009175),
LatLng(38.408209, 27.001965),
LatLng(38.405654, 26.994412),
LatLng(38.400138, 26.987889),
LatLng(38.395429, 26.973641),

]
],
points: const [
LatLng(-89, 0),
LatLng(89, 0),
LatLng(89, 179.999),
LatLng(-89, 179.999),
],
visible: true,
geodesic: false,
strokeWidth: 1,
consumeTapEvents: true,
onTap: (){
_showToast();
},
),
);

_polygons.add(
Polygon(
fillColor: Colors.black.withOpacity(0.5),
polygonId: const PolygonId('polyId2'),
points: const [
LatLng(-89.9, 0),
LatLng(89.9, 0),
LatLng(89.9, -179.999),
LatLng(-89.9, -179.999),
],
//onTap not working
visible: true,
geodesic: false,
strokeWidth: 1,
),
);

_polygons.add(
Polygon(

fillColor: Colors.black.withOpacity(0.5),
polygonId: const PolygonId('polyId3'),
points: const [
LatLng(38.372554, 26.973985),
LatLng(38.364344, 26.974843),
LatLng(38.365286, 26.983426),
LatLng(38.371478, 26.982053),
],
onTap: (){
_showToast();
},
consumeTapEvents: true,
visible: true,
geodesic: false,
strokeWidth: 1,
),
);
}

void setMarker(){
_markers.add(
Marker(
markerId: MarkerId('markerId1'),
position: LatLng(38.391455, 27.018199),
infoWindow: InfoWindow(
title: 'Marker1'
),
onTap: (){
fToast.removeQueuedCustomToasts();
}
)
);
_markers.add(
Marker(
markerId: MarkerId('markerId2'),
position: LatLng(38.376015, 26.950806),
infoWindow: InfoWindow(
title: 'Marker2'
),
onTap: (){
fToast.removeQueuedCustomToasts();
}
)
);
}



@override
Widget build(BuildContext context) {
return Scaffold(
body: GoogleMap(
myLocationEnabled: true,
myLocationButtonEnabled: false,
zoomControlsEnabled: true,
initialCameraPosition: CameraPosition(
target: LatLng(38.397498, 27.040055),
zoom: 11),
onMapCreated: (mapController) {
if (controller.isCompleted) {
controller.complete(mapController);
}
},
onTap: (latlng){
fToast.removeQueuedCustomToasts();
},
polygons: _polygons,
markers: Set<Marker>.of(_markers),
));
}

}

Thanks for reading this article

I wish it was helpful for you, for any question you can feel free to disturb poyrazahmetcan@hotmail.com

Read my other articles:

--

--

Ahmet Can Poyraz

Yasar University/Computer Engineering — Flutter Developer