Skip to content

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:

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

TechniqueMethodBest For
Solid fill + borderPolygon with fillColor + strokeColorDefault zones
Dashed borderPolyline with PatternItem.dashBoundaries, limits
Dotted borderPolyline with PatternItem.dotProposed areas
Stripe overlayMultiple Polyline on top of PolygonRestricted zones
TransparencyLow fillColor opacityBackground regions

Next Steps


Tip: Combine a semi-transparent Polygon fill with a Polyline border using PatternItem.dash for a professional "planned area" or "restricted zone" look.