apple_map_snapshotter 1.0.0 copy "apple_map_snapshotter: ^1.0.0" to clipboard
apple_map_snapshotter: ^1.0.0 copied to clipboard

PlatformiOS

Generate static Apple Maps snapshots on iOS using MapKit's MKMapSnapshotter. Perfect for displaying map previews without loading a full interactive map.

example/lib/main.dart

import 'dart:io';
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:apple_map_snapshotter/apple_map_snapshotter.dart';

void main() {
  runApp(const AppleMapSnapshotterExampleApp());
}

class AppleMapSnapshotterExampleApp extends StatelessWidget {
  const AppleMapSnapshotterExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Apple Map Snapshotter Example',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
        useMaterial3: true,
      ),
      home: const ExampleScreen(),
    );
  }
}

class ExampleScreen extends StatefulWidget {
  const ExampleScreen({super.key});

  @override
  State<ExampleScreen> createState() => _ExampleScreenState();
}

class _ExampleScreenState extends State<ExampleScreen> {
  Uint8List? _snapshotBytes;
  bool _isLoading = false;
  String? _error;
  AppleMapSnapshotTheme _selectedTheme = AppleMapSnapshotTheme.auto;
  double _zoomLevel = 13;

  // Example locations
  static const _locations = [
    _Location('San Francisco', 37.7749, -122.4194),
    _Location('New York', 40.7128, -74.0060),
    _Location('London', 51.5074, -0.1278),
    _Location('Paris', 48.8566, 2.3522),
    _Location('Tokyo', 35.6762, 139.6503),
  ];
  
  _Location _selectedLocation = _locations[0];

  @override
  void initState() {
    super.initState();
    _loadSnapshot();
  }

  Future<void> _loadSnapshot() async {
    if (!Platform.isIOS) {
      setState(() {
        _error = 'This plugin only works on iOS';
        _isLoading = false;
      });
      return;
    }

    setState(() {
      _isLoading = true;
      _error = null;
    });

    try {
      final bytes = await AppleMapSnapshotter.getSnapshot(
        latitude: _selectedLocation.latitude,
        longitude: _selectedLocation.longitude,
        width: 350,
        height: 250,
        zoomLevel: _zoomLevel,
        theme: _selectedTheme,
      );

      setState(() {
        _snapshotBytes = bytes;
        _isLoading = false;
      });
    } catch (e) {
      setState(() {
        _error = e.toString();
        _isLoading = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Map Snapshotter'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // Location selector
            Card(
              child: Padding(
                padding: const EdgeInsets.all(16),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text(
                      'Location',
                      style: TextStyle(
                        fontSize: 16,
                        fontWeight: FontWeight.w600,
                      ),
                    ),
                    const SizedBox(height: 8),
                    DropdownButtonFormField<_Location>(
                      value: _selectedLocation,
                      decoration: const InputDecoration(
                        border: OutlineInputBorder(),
                        contentPadding: EdgeInsets.symmetric(
                          horizontal: 12,
                          vertical: 8,
                        ),
                      ),
                      items: _locations.map((loc) {
                        return DropdownMenuItem(
                          value: loc,
                          child: Text(loc.name),
                        );
                      }).toList(),
                      onChanged: (value) {
                        if (value != null) {
                          setState(() => _selectedLocation = value);
                        }
                      },
                    ),
                    const SizedBox(height: 8),
                    Text(
                      'Lat: ${_selectedLocation.latitude.toStringAsFixed(4)}, '
                      'Lng: ${_selectedLocation.longitude.toStringAsFixed(4)}',
                      style: TextStyle(color: Colors.grey[600], fontSize: 12),
                    ),
                  ],
                ),
              ),
            ),

            const SizedBox(height: 16),

            // Theme selector
            Card(
              child: Padding(
                padding: const EdgeInsets.all(16),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text(
                      'Theme',
                      style: TextStyle(
                        fontSize: 16,
                        fontWeight: FontWeight.w600,
                      ),
                    ),
                    const SizedBox(height: 8),
                    SegmentedButton<AppleMapSnapshotTheme>(
                      segments: const [
                        ButtonSegment(
                          value: AppleMapSnapshotTheme.auto,
                          label: Text('Auto'),
                        ),
                        ButtonSegment(
                          value: AppleMapSnapshotTheme.light,
                          label: Text('Light'),
                        ),
                        ButtonSegment(
                          value: AppleMapSnapshotTheme.dark,
                          label: Text('Dark'),
                        ),
                      ],
                      selected: {_selectedTheme},
                      onSelectionChanged: (Set<AppleMapSnapshotTheme> selected) {
                        setState(() => _selectedTheme = selected.first);
                      },
                    ),
                  ],
                ),
              ),
            ),

            const SizedBox(height: 16),

            // Zoom slider
            Card(
              child: Padding(
                padding: const EdgeInsets.all(16),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        const Text(
                          'Zoom Level',
                          style: TextStyle(
                            fontSize: 16,
                            fontWeight: FontWeight.w600,
                          ),
                        ),
                        Text(
                          _zoomLevel.toStringAsFixed(1),
                          style: TextStyle(
                            color: Colors.grey[600],
                            fontWeight: FontWeight.w500,
                          ),
                        ),
                      ],
                    ),
                    Slider(
                      value: _zoomLevel,
                      min: 0,
                      max: 20,
                      divisions: 40,
                      onChanged: (value) {
                        setState(() => _zoomLevel = value);
                      },
                    ),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Text('World', style: TextStyle(color: Colors.grey[500], fontSize: 12)),
                        Text('Street', style: TextStyle(color: Colors.grey[500], fontSize: 12)),
                      ],
                    ),
                  ],
                ),
              ),
            ),

            const SizedBox(height: 16),

            // Generate button
            FilledButton.icon(
              onPressed: _isLoading ? null : _loadSnapshot,
              icon: _isLoading
                  ? const SizedBox(
                      width: 20,
                      height: 20,
                      child: CircularProgressIndicator(
                        strokeWidth: 2,
                        color: Colors.white,
                      ),
                    )
                  : const Icon(Icons.map),
              label: Text(_isLoading ? 'Generating...' : 'Generate Snapshot'),
            ),

            const SizedBox(height: 24),

            // Snapshot display
            if (_error != null)
              Container(
                padding: const EdgeInsets.all(16),
                decoration: BoxDecoration(
                  color: Colors.red[50],
                  borderRadius: BorderRadius.circular(12),
                  border: Border.all(color: Colors.red[200]!),
                ),
                child: Row(
                  children: [
                    Icon(Icons.error_outline, color: Colors.red[700]),
                    const SizedBox(width: 12),
                    Expanded(
                      child: Text(
                        _error!,
                        style: TextStyle(color: Colors.red[700]),
                      ),
                    ),
                  ],
                ),
              )
            else if (_snapshotBytes != null)
              Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  const Text(
                    'Generated Snapshot',
                    style: TextStyle(
                      fontSize: 16,
                      fontWeight: FontWeight.w600,
                    ),
                  ),
                  const SizedBox(height: 12),
                  ClipRRect(
                    borderRadius: BorderRadius.circular(12),
                    child: Image.memory(
                      _snapshotBytes!,
                      width: double.infinity,
                      fit: BoxFit.cover,
                    ),
                  ),
                  const SizedBox(height: 8),
                  Text(
                    'Size: ${(_snapshotBytes!.lengthInBytes / 1024).toStringAsFixed(1)} KB',
                    style: TextStyle(color: Colors.grey[600], fontSize: 12),
                  ),
                ],
              )
            else if (!_isLoading)
              Container(
                height: 200,
                decoration: BoxDecoration(
                  color: Colors.grey[200],
                  borderRadius: BorderRadius.circular(12),
                ),
                child: const Center(
                  child: Text('Tap "Generate Snapshot" to create a map'),
                ),
              ),
          ],
        ),
      ),
    );
  }
}

class _Location {
  final String name;
  final double latitude;
  final double longitude;

  const _Location(this.name, this.latitude, this.longitude);

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is _Location &&
          runtimeType == other.runtimeType &&
          name == other.name;

  @override
  int get hashCode => name.hashCode;
}
1
likes
140
points
56
downloads

Publisher

unverified uploader

Weekly Downloads

Generate static Apple Maps snapshots on iOS using MapKit's MKMapSnapshotter. Perfect for displaying map previews without loading a full interactive map.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on apple_map_snapshotter

Packages that implement apple_map_snapshotter