map_location_picker 2.0.3 copy "map_location_picker: ^2.0.3" to clipboard
map_location_picker: ^2.0.3 copied to clipboard

Google Map location picker for flutter Based on google_maps_flutter.

example/lib/main.dart

import 'package:example/key.dart';
import 'package:flutter/material.dart';
import 'package:map_location_picker/map_location_picker.dart';

void main() => runApp(const MyApp());

final _themeMode = ValueNotifier<ThemeMode>(ThemeMode.light);

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

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<ThemeMode>(
      valueListenable: _themeMode,
      builder: (context, themeMode, child) {
        return MaterialApp(
          title: 'Location Picker Demo',
          theme: ThemeData.light(),
          darkTheme: ThemeData.dark(),
          themeMode: themeMode,
          home: const LocationPickerScreen(),
          debugShowCheckedModeBanner: false,
        );
      },
    );
  }
}

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

  @override
  State<LocationPickerScreen> createState() => _LocationPickerScreenState();
}

class _LocationPickerScreenState extends State<LocationPickerScreen> {
  LatLng? _pickedLocation;
  String _formattedAddress = "No location selected";
  BitmapDescriptor? _customMarkerIcon;

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

  void _createMarkerIcon() async {
    _customMarkerIcon = await BitmapDescriptor.asset(
      const ImageConfiguration(size: Size(48, 48)),
      'assets/marker.webp', // Replace with your marker asset
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Location Picker'),
        centerTitle: true,
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // Map Preview Section
            Container(
              decoration: BoxDecoration(
                border: Border.all(
                  color: Theme.of(context).brightness == Brightness.dark
                      ? Colors.grey.shade700
                      : Colors.grey.shade300,
                ),
                borderRadius: BorderRadius.circular(12),
              ),
              margin: const EdgeInsets.only(bottom: 16),
              height: (MediaQuery.of(context).size.height / 5),
              width: MediaQuery.of(context).size.width,
              child: ClipRRect(
                  borderRadius: BorderRadius.circular(12),
                  child: (_pickedLocation == null
                      ? const Center(
                          child: Text('Select a location to preview'),
                        )
                      : Image.network(
                          googleStaticMapWithMarker(
                            _pickedLocation!.latitude,
                            _pickedLocation!.longitude,
                            18,
                            apiKey: YOUR_API_KEY,
                          ),
                          fit: BoxFit.cover,
                          width: MediaQuery.of(context).size.width,
                          height: (MediaQuery.of(context).size.height / 5),
                        ))),
            ),

            // Formatted Address Section
            Container(
              padding: const EdgeInsets.all(16),
              decoration: BoxDecoration(
                color: Theme.of(context).brightness == Brightness.dark
                    ? Colors.grey.shade900
                    : Colors.grey.shade100,
                borderRadius: BorderRadius.circular(12),
              ),
              margin: const EdgeInsets.only(bottom: 16),
              child: Row(
                children: [
                  const Icon(Icons.location_on, color: Colors.blue),
                  const SizedBox(width: 12),
                  Expanded(
                    child: Text(
                      _formattedAddress,
                      style: const TextStyle(fontSize: 16),
                      maxLines: 2,
                      overflow: TextOverflow.ellipsis,
                    ),
                  ),
                ],
              ),
            ),

            // Options Section
            Column(
              children: [
                const Text(
                  "PICK LOCATION OPTIONS",
                  style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
                ),
                const SizedBox(height: 16),

                // Standard Picker
                _buildOptionCard(
                  icon: Icons.map,
                  title: "Standard Map Picker",
                  description: "Open map with default settings",
                  onTap: () => _openLocationPicker(
                    const MapLocationPickerConfig(
                      apiKey: YOUR_API_KEY,
                    ),
                  ),
                ),

                // Dark Theme Picker
                _buildOptionCard(
                  icon: Icons.dark_mode,
                  title: "Dark Theme Picker",
                  description: "Open map with dark theme",
                  onTap: () async {
                    _themeMode.value = ThemeMode.dark;
                    await _openLocationPicker(
                      MapLocationPickerConfig(
                        apiKey: YOUR_API_KEY,
                        mapStyle: _darkMapStyle,
                      ),
                    );
                    _themeMode.value = ThemeMode.light;
                  },
                ),

                // Satellite View Picker
                _buildOptionCard(
                  icon: Icons.satellite,
                  title: "Satellite View",
                  description: "Open with satellite imagery",
                  onTap: () => _openLocationPicker(
                    const MapLocationPickerConfig(
                      apiKey: YOUR_API_KEY,
                      initialMapType: MapType.satellite,
                    ),
                  ),
                ),

                // Custom Markers Picker
                _buildOptionCard(
                  icon: Icons.pin_drop,
                  title: "Custom Markers",
                  description: "Add custom markers to the map",
                  onTap: () => _openLocationPicker(
                    MapLocationPickerConfig(
                      apiKey: YOUR_API_KEY,
                      mainMarkerIcon: _customMarkerIcon,
                      additionalMarkers: const {
                        "landmark1": LatLng(37.422, -122.084),
                        "landmark2": LatLng(37.426, -122.083),
                      },
                      customMarkerIcons: {
                        "landmark1": BitmapDescriptor.defaultMarkerWithHue(
                          BitmapDescriptor.hueYellow,
                        ),
                        "landmark2": BitmapDescriptor.defaultMarkerWithHue(
                          BitmapDescriptor.hueBlue,
                        ),
                      },
                    ),
                  ),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildOptionCard({
    required IconData icon,
    required String title,
    required String description,
    required VoidCallback onTap,
  }) {
    return Card(
      margin: const EdgeInsets.only(bottom: 16),
      elevation: 0.2,
      child: InkWell(
        onTap: onTap,
        borderRadius: BorderRadius.circular(12),
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Row(
            children: [
              Icon(icon, size: 36, color: Colors.blue),
              const SizedBox(width: 16),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      title,
                      style: const TextStyle(
                        fontWeight: FontWeight.bold,
                        fontSize: 16,
                      ),
                    ),
                    const SizedBox(height: 4),
                    Text(
                      description,
                      style: TextStyle(color: Colors.grey.shade600),
                    ),
                  ],
                ),
              ),
              const Icon(Icons.chevron_right, size: 30),
            ],
          ),
        ),
      ),
    );
  }

  Future<void> _openLocationPicker(MapLocationPickerConfig config) async {
    await Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => MapLocationPicker(
          config: config.copyWith(
            initialPosition: _pickedLocation ?? const LatLng(37.422, -122.084),
            onNext: (result) {
              if (result != null) {
                setState(() {
                  _pickedLocation = LatLng(
                    result.geometry.location.lat,
                    result.geometry.location.lng,
                  );
                  _formattedAddress =
                      result.formattedAddress ?? "Address not available";
                });
              }
              if (context.mounted) {
                Navigator.pop(context, result);
              }
            },
          ),
          searchConfig: const SearchConfig(
            apiKey: YOUR_API_KEY,
            searchHintText: "Search for a location",
          ),
        ),
      ),
    );
  }

  // Dark map style JSON (truncated for brevity)
  final String _darkMapStyle = '''
[
  {
    "elementType": "geometry",
    "stylers": [
      { "color": "#212121" }
    ]
  },
  {
    "elementType": "labels.icon",
    "stylers": [
      { "visibility": "off" }
    ]
  },
  {
    "elementType": "labels.text.fill",
    "stylers": [
      { "color": "#757575" }
    ]
  },
  {
    "elementType": "labels.text.stroke",
    "stylers": [
      { "color": "#212121" }
    ]
  },
  {
    "featureType": "administrative",
    "elementType": "geometry",
    "stylers": [
      { "color": "#757575" }
    ]
  },
  {
    "featureType": "poi",
    "elementType": "geometry",
    "stylers": [
      { "color": "#313131" }
    ]
  },
  {
    "featureType": "poi.park",
    "elementType": "geometry",
    "stylers": [
      { "color": "#263c3f" }
    ]
  },
  {
    "featureType": "road",
    "elementType": "geometry.fill",
    "stylers": [
      { "color": "#2c2c2c" }
    ]
  },
  {
    "featureType": "road",
    "elementType": "geometry.stroke",
    "stylers": [
      { "color": "#212121" }
    ]
  },
  {
    "featureType": "road",
    "elementType": "labels.text.fill",
    "stylers": [
      { "color": "#8a8a8a" }
    ]
  },
  {
    "featureType": "transit",
    "elementType": "geometry",
    "stylers": [
      { "color": "#2f3948" }
    ]
  },
  {
    "featureType": "water",
    "elementType": "geometry",
    "stylers": [
      { "color": "#000000" }
    ]
  },
  {
    "featureType": "water",
    "elementType": "labels.text.fill",
    "stylers": [
      { "color": "#3d3d3d" }
    ]
  }
]
  ''';
}