Add a Pattern to a Polygon in Flutter
This tutorial shows how to create patterned polygon fills — stripes, crosshatch, dots, or custom patterns — instead of a plain solid color.
Prerequisites
Before you begin, ensure you have:
- Completed the Flutter Setup Guide
- A MapMetrics API key and style URL from the MapMetrics Portal
Striped Polygon Using Overlapping Lines
Simulate a striped pattern by overlaying diagonal lines on top of a filled polygon:
dart
import 'package:flutter/material.dart';
import 'package:mapmetrics/mapmetrics.dart';
class StripedPolygonScreen extends StatefulWidget {
@override
_StripedPolygonScreenState createState() => _StripedPolygonScreenState();
}
class _StripedPolygonScreenState extends State<StripedPolygonScreen> {
MapMetricsController? mapController;
final List<LatLng> regionPoints = [
LatLng(48.88, 2.28),
LatLng(48.88, 2.40),
LatLng(48.82, 2.40),
LatLng(48.82, 2.28),
LatLng(48.88, 2.28), // close
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Striped Polygon')),
body: MapMetrics(
styleUrl:
'https://gateway.mapmetrics.org/styles/YOUR_STYLE_ID?token=YOUR_API_KEY',
onMapCreated: (MapMetricsController controller) {
mapController = controller;
},
initialCameraPosition: CameraPosition(
target: LatLng(48.85, 2.34),
zoom: 12.0,
),
polygons: {
// Semi-transparent fill
Polygon(
polygonId: PolygonId('region_fill'),
points: regionPoints,
fillColor: Colors.blue.withOpacity(0.15),
strokeColor: Colors.blue,
strokeWidth: 2,
),
},
polylines: _buildStripeLines(),
),
);
}
/// Generate diagonal stripe lines across the polygon area
Set<Polyline> _buildStripeLines() {
final stripes = <Polyline>{};
final step = 0.008; // spacing between stripes
// Generate diagonal lines from bottom-left to top-right
for (double offset = -0.15; offset < 0.25; offset += step) {
final lat1 = 48.82;
final lng1 = 2.28 + offset;
final lat2 = 48.88;
final lng2 = 2.28 + offset + 0.06;
// Only draw if within polygon bounds
if (lng1 < 2.40 || lng2 > 2.28) {
stripes.add(
Polyline(
polylineId: PolylineId('stripe_${offset.toStringAsFixed(3)}'),
points: [
LatLng(lat1, lng1.clamp(2.28, 2.40)),
LatLng(lat2, lng2.clamp(2.28, 2.40)),
],
color: Colors.blue.withOpacity(0.3),
width: 1,
),
);
}
}
return stripes;
}
}Dashed Border Polygon
Use dashed polyline borders around a filled polygon:
dart
import 'package:flutter/material.dart';
import 'package:mapmetrics/mapmetrics.dart';
class DashedPolygonScreen extends StatefulWidget {
@override
_DashedPolygonScreenState createState() => _DashedPolygonScreenState();
}
class _DashedPolygonScreenState extends State<DashedPolygonScreen> {
MapMetricsController? mapController;
final List<LatLng> area = [
LatLng(48.870, 2.300),
LatLng(48.870, 2.370),
LatLng(48.840, 2.370),
LatLng(48.840, 2.300),
LatLng(48.870, 2.300),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Dashed Border Polygon')),
body: MapMetrics(
styleUrl:
'https://gateway.mapmetrics.org/styles/YOUR_STYLE_ID?token=YOUR_API_KEY',
onMapCreated: (MapMetricsController controller) {
mapController = controller;
},
initialCameraPosition: CameraPosition(
target: LatLng(48.855, 2.335),
zoom: 13.0,
),
polygons: {
Polygon(
polygonId: PolygonId('dashed_area'),
points: area,
fillColor: Colors.orange.withOpacity(0.15),
strokeWidth: 0, // no solid stroke
),
},
polylines: {
Polyline(
polylineId: PolylineId('dashed_border'),
points: area,
color: Colors.orange,
width: 3,
patterns: [PatternItem.dash(15), PatternItem.gap(10)],
),
},
),
);
}
}Multiple Pattern Styles
Show several polygons with different visual patterns:
dart
import 'package:flutter/material.dart';
import 'package:mapmetrics/mapmetrics.dart';
class MultiPatternScreen extends StatefulWidget {
@override
_MultiPatternScreenState createState() => _MultiPatternScreenState();
}
class _MultiPatternScreenState extends State<MultiPatternScreen> {
MapMetricsController? mapController;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Pattern Styles')),
body: Stack(
children: [
MapMetrics(
styleUrl:
'https://gateway.mapmetrics.org/styles/YOUR_STYLE_ID?token=YOUR_API_KEY',
onMapCreated: (MapMetricsController controller) {
mapController = controller;
},
initialCameraPosition: CameraPosition(
target: LatLng(48.855, 2.335),
zoom: 12.5,
),
polygons: {
// Zone A: Solid fill
Polygon(
polygonId: PolygonId('solid'),
points: [
LatLng(48.870, 2.280), LatLng(48.870, 2.320),
LatLng(48.855, 2.320), LatLng(48.855, 2.280),
LatLng(48.870, 2.280),
],
fillColor: Colors.blue.withOpacity(0.3),
strokeColor: Colors.blue,
strokeWidth: 2,
),
// Zone B: Light with thick border
Polygon(
polygonId: PolygonId('thick_border'),
points: [
LatLng(48.870, 2.330), LatLng(48.870, 2.370),
LatLng(48.855, 2.370), LatLng(48.855, 2.330),
LatLng(48.870, 2.330),
],
fillColor: Colors.green.withOpacity(0.1),
strokeColor: Colors.green,
strokeWidth: 4,
),
// Zone C: Very transparent
Polygon(
polygonId: PolygonId('transparent'),
points: [
LatLng(48.850, 2.280), LatLng(48.850, 2.320),
LatLng(48.835, 2.320), LatLng(48.835, 2.280),
LatLng(48.850, 2.280),
],
fillColor: Colors.red.withOpacity(0.05),
strokeColor: Colors.red,
strokeWidth: 2,
),
},
polylines: {
// Zone D: Dotted border
Polyline(
polylineId: PolylineId('dotted_border'),
points: [
LatLng(48.850, 2.330), LatLng(48.850, 2.370),
LatLng(48.835, 2.370), LatLng(48.835, 2.330),
LatLng(48.850, 2.330),
],
color: Colors.purple,
width: 3,
patterns: [PatternItem.dot],
),
},
),
// Legend
Positioned(
bottom: 16,
left: 16,
child: Card(
child: Padding(
padding: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text('Zones',
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 12)),
_legendRow(Colors.blue, 'A: Solid fill'),
_legendRow(Colors.green, 'B: Thick border'),
_legendRow(Colors.red, 'C: Transparent'),
_legendRow(Colors.purple, 'D: Dotted border'),
],
),
),
),
),
],
),
);
}
Widget _legendRow(Color color, String label) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 1),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 14,
height: 14,
decoration: BoxDecoration(
color: color.withOpacity(0.3),
border: Border.all(color: color, width: 1.5),
)),
SizedBox(width: 6),
Text(label, style: TextStyle(fontSize: 11)),
],
),
);
}
}Pattern Techniques
| Technique | Method | Best For |
|---|---|---|
| Solid fill + border | Polygon with fillColor + strokeColor | Default zones |
| Dashed border | Polyline with PatternItem.dash | Boundaries, limits |
| Dotted border | Polyline with PatternItem.dot | Proposed areas |
| Stripe overlay | Multiple Polyline on top of Polygon | Restricted zones |
| Transparency | Low fillColor opacity | Background regions |
Next Steps
- Add a Polygon — Basic polygon drawing
- Add a GeoJSON Polygon — GeoJSON-based polygons
- Show Polygon Info on Click — Interactive polygons
Tip: Combine a semi-transparent Polygon fill with a Polyline border using PatternItem.dash for a professional "planned area" or "restricted zone" look.