Custom Map Styling with Flutter and MapMetrics 
This tutorial will show you how to create custom map styles and integrate them with your Flutter MapMetrics applications.
Using MapMetrics Portal for Custom Styles 
The MapMetrics Portal provides an intuitive interface for creating custom map styles that work seamlessly with Flutter applications.
Step 1: Create a Custom Style 
- Visit MapMetrics Portal: Go to portal.mapmetrics.org
 - Navigate to Styles: Click on the "Styles" section
 - Create New Style: Click "New Style" and choose a template
 - Customize Your Style: Use the visual editor to modify: 
- Colors and themes
 - Fonts and typography
 - Map features (roads, buildings, water, etc.)
 - Icons and symbols
 
 - Save and Get URL: Save your style and copy the style URL
 
Step 2: Use Custom Style in Flutter 
dart
import 'package:flutter/material.dart';
import 'package:mapmetrics/mapmetrics.dart';
class CustomStyledMapScreen extends StatefulWidget {
  @override
  _CustomStyledMapScreenState createState() => _CustomStyledMapScreenState();
}
class _CustomStyledMapScreenState extends State<CustomStyledMapScreen> {
  MapMetricsController? mapController;
  String currentStyleUrl = '';
  // Different style URLs from MapMetrics Portal
  final Map<String, String> styleOptions = {
    'Dark Theme': 'https://gateway.mapmetrics.org/styles/YOUR_DARK_STYLE_ID?token=YOUR_API_KEY',
    'Light Theme': 'https://gateway.mapmetrics.org/styles/YOUR_LIGHT_STYLE_ID?token=YOUR_API_KEY',
    'Satellite': 'https://gateway.mapmetrics.org/styles/YOUR_SATELLITE_STYLE_ID?token=YOUR_API_KEY',
    'Custom Brand': 'https://gateway.mapmetrics.org/styles/YOUR_CUSTOM_STYLE_ID?token=YOUR_API_KEY',
  };
  @override
  void initState() {
    super.initState();
    currentStyleUrl = styleOptions.values.first;
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Custom Styled Map'),
        actions: [
          PopupMenuButton<String>(
            onSelected: _changeStyle,
            itemBuilder: (context) => styleOptions.keys.map((String key) {
              return PopupMenuItem<String>(
                value: key,
                child: Text(key),
              );
            }).toList(),
            child: Padding(
              padding: EdgeInsets.all(16.0),
              child: Icon(Icons.style),
            ),
          ),
        ],
      ),
      body: MapMetrics(
        styleUrl: currentStyleUrl,
        onMapCreated: (MapMetricsController controller) {
          setState(() {
            mapController = controller;
          });
        },
        onStyleLoaded: () {
          print('Custom style loaded successfully!');
        },
        initialCameraPosition: CameraPosition(
          target: LatLng(40.7128, -74.0060),
          zoom: 12.0,
        ),
      ),
    );
  }
  void _changeStyle(String styleName) {
    setState(() {
      currentStyleUrl = styleOptions[styleName] ?? currentStyleUrl;
    });
  }
}Dynamic Style Switching 
Smooth Style Transitions 
dart
class DynamicStyleScreen extends StatefulWidget {
  @override
  _DynamicStyleScreenState createState() => _DynamicStyleScreenState();
}
class _DynamicStyleScreenState extends State<DynamicStyleScreen> {
  MapMetricsController? mapController;
  bool isDarkMode = false;
  String get currentStyleUrl => isDarkMode
      ? 'https://gateway.mapmetrics.org/styles/YOUR_DARK_STYLE_ID?token=YOUR_API_KEY'
      : 'https://gateway.mapmetrics.org/styles/YOUR_LIGHT_STYLE_ID?token=YOUR_API_KEY';
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Dynamic Style Switching'),
        actions: [
          Switch(
            value: isDarkMode,
            onChanged: (value) {
              setState(() {
                isDarkMode = value;
              });
              _updateMapStyle();
            },
          ),
        ],
      ),
      body: MapMetrics(
        styleUrl: currentStyleUrl,
        onMapCreated: (controller) => mapController = controller,
        onStyleLoaded: () => print('Style loaded'),
        initialCameraPosition: CameraPosition(
          target: LatLng(40.7128, -74.0060),
          zoom: 12.0,
        ),
      ),
    );
  }
  void _updateMapStyle() {
    mapController?.setStyleString(currentStyleUrl);
  }
}Custom Map Layers 
Adding Custom Overlays 
dart
class CustomLayersScreen extends StatefulWidget {
  @override
  _CustomLayersScreenState createState() => _CustomLayersScreenState();
}
class _CustomLayersScreenState extends State<CustomLayersScreen> {
  MapMetricsController? mapController;
  Set<Circle> customLayers = {};
  @override
  void initState() {
    super.initState();
    _initializeCustomLayers();
  }
  void _initializeCustomLayers() {
    customLayers = {
      Circle(
        circleId: CircleId('highlight_area'),
        center: LatLng(40.7128, -74.0060),
        radius: 2000,
        strokeWidth: 3,
        strokeColor: Colors.blue,
        fillColor: Colors.blue.withOpacity(0.1),
      ),
      Circle(
        circleId: CircleId('restricted_zone'),
        center: LatLng(40.7589, -73.9851),
        radius: 1000,
        strokeWidth: 2,
        strokeColor: Colors.red,
        fillColor: Colors.red.withOpacity(0.2),
      ),
    };
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Custom Layers')),
      body: MapMetrics(
        styleUrl: 'https://gateway.mapmetrics.org/styles/YOUR_STYLE_ID?token=YOUR_API_KEY',
        onMapCreated: (controller) => mapController = controller,
        initialCameraPosition: CameraPosition(
          target: LatLng(40.7128, -74.0060),
          zoom: 12.0,
        ),
        circles: customLayers,
      ),
    );
  }
}Branded Map Styles 
Creating Brand-Consistent Maps 
dart
class BrandedMapScreen extends StatefulWidget {
  @override
  _BrandedMapScreenState createState() => _BrandedMapScreenState();
}
class _BrandedMapScreenState extends State<BrandedMapScreen> {
  MapMetricsController? mapController;
  // Brand colors
  final Color primaryColor = Color(0xFF1E88E5);
  final Color secondaryColor = Color(0xFF42A5F5);
  final Color accentColor = Color(0xFFFF5722);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Branded Map'),
        backgroundColor: primaryColor,
      ),
      body: Stack(
        children: [
          MapMetrics(
            styleUrl: 'https://gateway.mapmetrics.org/styles/YOUR_BRANDED_STYLE_ID?token=YOUR_API_KEY',
            onMapCreated: (controller) => mapController = controller,
            initialCameraPosition: CameraPosition(
              target: LatLng(40.7128, -74.0060),
              zoom: 12.0,
            ),
          ),
          // Custom branded overlay
          Positioned(
            top: 20,
            right: 20,
            child: Container(
              padding: EdgeInsets.all(12),
              decoration: BoxDecoration(
                color: primaryColor.withOpacity(0.9),
                borderRadius: BorderRadius.circular(8),
                boxShadow: [
                  BoxShadow(
                    color: Colors.black26,
                    blurRadius: 4,
                    offset: Offset(0, 2),
                  ),
                ],
              ),
              child: Text(
                'Your Brand',
                style: TextStyle(
                  color: Colors.white,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}Style Configuration Options 
Advanced Style Settings 
dart
class AdvancedStyleScreen extends StatefulWidget {
  @override
  _AdvancedStyleScreenState createState() => _AdvancedStyleScreenState();
}
class _AdvancedStyleScreenState extends State<AdvancedStyleScreen> {
  MapMetricsController? mapController;
  bool showBuildings = true;
  bool showLabels = true;
  bool showRoads = true;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Advanced Style Options')),
      body: Column(
        children: [
          // Style controls
          Container(
            padding: EdgeInsets.all(16),
            color: Colors.grey[100],
            child: Column(
              children: [
                SwitchListTile(
                  title: Text('Show Buildings'),
                  value: showBuildings,
                  onChanged: (value) {
                    setState(() {
                      showBuildings = value;
                    });
                    _updateMapStyle();
                  },
                ),
                SwitchListTile(
                  title: Text('Show Labels'),
                  value: showLabels,
                  onChanged: (value) {
                    setState(() {
                      showLabels = value;
                    });
                    _updateMapStyle();
                  },
                ),
                SwitchListTile(
                  title: Text('Show Roads'),
                  value: showRoads,
                  onChanged: (value) {
                    setState(() {
                      showRoads = value;
                    });
                    _updateMapStyle();
                  },
                ),
              ],
            ),
          ),
          // Map
          Expanded(
            child: MapMetrics(
              styleUrl: 'https://gateway.mapmetrics.org/styles/YOUR_STYLE_ID?token=YOUR_API_KEY',
              onMapCreated: (controller) => mapController = controller,
              initialCameraPosition: CameraPosition(
                target: LatLng(40.7128, -74.0060),
                zoom: 15.0,
              ),
            ),
          ),
        ],
      ),
    );
  }
  void _updateMapStyle() {
    // You can programmatically modify style layers here
    // This would require additional MapMetrics GL JS functionality
    print('Style updated: Buildings=$showBuildings, Labels=$showLabels, Roads=$showRoads');
  }
}Performance Optimization 
Style Loading Optimization 
dart
class OptimizedStyleScreen extends StatefulWidget {
  @override
  _OptimizedStyleScreenState createState() => _OptimizedStyleScreenState();
}
class _OptimizedStyleScreenState extends State<OptimizedStyleScreen> {
  MapMetricsController? mapController;
  bool isStyleLoaded = false;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Optimized Style Loading')),
      body: Stack(
        children: [
          MapMetrics(
            styleUrl: 'https://gateway.mapmetrics.org/styles/YOUR_STYLE_ID?token=YOUR_API_KEY',
            onMapCreated: (controller) => mapController = controller,
            onStyleLoaded: () {
              setState(() {
                isStyleLoaded = true;
              });
            },
            initialCameraPosition: CameraPosition(
              target: LatLng(40.7128, -74.0060),
              zoom: 12.0,
            ),
          ),
          // Loading indicator
          if (!isStyleLoaded)
            Container(
              color: Colors.white,
              child: Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    CircularProgressIndicator(),
                    SizedBox(height: 16),
                    Text('Loading custom map style...'),
                  ],
                ),
              ),
            ),
        ],
      ),
    );
  }
}Best Practices 
Style Design Tips 
- Consistency: Use consistent colors and fonts across your app and map
 - Accessibility: Ensure sufficient contrast for text and important features
 - Performance: Keep style complexity reasonable for smooth rendering
 - Branding: Integrate your brand colors and elements naturally
 - Testing: Test your styles on different devices and screen sizes
 
Style Management 
dart
class StyleManager {
  static const Map<String, String> predefinedStyles = {
    'default': 'https://gateway.mapmetrics.org/styles/DEFAULT_STYLE_ID?token=YOUR_API_KEY',
    'dark': 'https://gateway.mapmetrics.org/styles/DARK_STYLE_ID?token=YOUR_API_KEY',
    'satellite': 'https://gateway.mapmetrics.org/styles/SATELLITE_STYLE_ID?token=YOUR_API_KEY',
    'minimal': 'https://gateway.mapmetrics.org/styles/MINIMAL_STYLE_ID?token=YOUR_API_KEY',
  };
  static String getStyleUrl(String styleName) {
    return predefinedStyles[styleName] ?? predefinedStyles['default']!;
  }
  static bool isValidStyleUrl(String url) {
    return url.startsWith('https://gateway.mapmetrics.org/styles/') && 
           url.contains('token=');
  }
}Next Steps 
Now that you understand custom styling, try:
Pro Tip: Use the MapMetrics Portal's style editor to create multiple variations of your map style for different use cases (dark mode, minimal view, detailed view, etc.).