map_location_picker 2.0.0+1
map_location_picker: ^2.0.0+1 copied to clipboard
Google Map location picker for flutter Based on google_maps_flutter.
map_location_picker: #
Modern Location Picker for Flutter with Enhanced UI & Customization #
Version 2.0 introduces a complete overhaul with:
Check migration guide from 1.x to 2.x map_location_picker/MIGRATION_GUIDE
- π New Cupertino-style UI components
- π Built-in dark/light theme support
- π§© Modular configuration architecture
- π Performance optimizations
- πΊοΈ Advanced map customization options
- π§ Improved navigation and UI flow
Check out the more screenshots here
Map Preview | Address Display | Picker Options |
![]() |
![]() |
![]() |
π Getting Started #
Installation #
Add to your pubspec.yaml
:
dependencies:
map_location_picker: ^2.0.0
Setup Guide #
-
Get an API key at https://cloud.google.com/maps-platform/.
-
And don't forget to enable the following APIs in https://console.cloud.google.com/google/maps-apis/
- Maps SDK for Android
- Maps SDK for iOS
- Places API
- Geocoding API
- Maps JavaScript API
-
And ensure to enable billing for the project.
For more details, see Getting started with Google Maps Platform.
Android #
- Set the
minSdkVersion
inandroid/app/build.gradle
:
android {
defaultConfig {
minSdkVersion 20
}
}
This means that app will only be available for users that run Android SDK 20 or higher.
- Specify your API key in the application manifest
android/app/src/main/AndroidManifest.xml
:
<manifest ...
<application ...
<meta-data android:name="com.google.android.geo.API_KEY"
android:value="YOUR KEY HERE"/>
Hybrid Composition
To use Hybrid Composition
to render the GoogleMap
widget on Android, set AndroidGoogleMapsFlutter.useAndroidViewSurface
to
true.
if (defaultTargetPlatform == TargetPlatform.android) {
AndroidGoogleMapsFlutter.useAndroidViewSurface = true;
}
iOS #
To set up, specify your API key in the application delegate ios/Runner/AppDelegate.m
:
#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"
#import "GoogleMaps/GoogleMaps.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GMSServices provideAPIKey:@"YOUR KEY HERE"];
[GeneratedPluginRegistrant registerWithRegistry:self];
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end
Or in your swift code, specify your API key in the application delegate ios/Runner/AppDelegate.swift
:
import UIKit
import Flutter
import GoogleMaps
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GMSServices.provideAPIKey("YOUR KEY HERE")
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
Recommended: Restricting Api Keys to your Android or IOS bundle identifiers: #
You must then send the following in the headers:
Map<String, String> headers = {};
if (Platform.isIOS || Platform.isMacOS) {
headers['X-Ios-Bundle-Identifier'] = 'Your Bundle Identifier';
}
if (Platform.isAndroid) {
headers['X-Android-Package'] = 'Your Bundle Identifier';
headers['X-Android-Cert'] = 'Your Sha-1';
}
MapLocationPicker(
geoCodingApiHeaders: headers,
...
)
Web View #
Modify web/index.html
Get an API Key for Google Maps JavaScript API. Get started here.
Modify the <head>
tag of your web/index.html
to load the Google Maps JavaScript API, like so:
<head>
<!-- // Other stuff -->
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"></script>
</head>
Note #
The following permissions are not required to use Google Maps Android API v2, but are recommended.
android.permission.ACCESS_COARSE_LOCATION
Allows the API to use WiFi or mobile cell data (or both) to determine the
device's location. The API returns the location with an accuracy approximately equivalent to a city block.
android.permission.ACCESS_FINE_LOCATION
Allows the API to determine as precise a location as possible from the
available location providers, including the Global Positioning System (GPS) as well as WiFi and mobile cell data.
You must also explicitly declare that your app uses the android.hardware.location.network or android.hardware.location.gps hardware features if your app targets Android 5.0 (API level 21) or higher and uses the ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission in order to receive location updates from the network or a GPS, respectively.
<uses-feature android:name="android.hardware.location.network" android:required="false"/>
<uses-feature android:name="android.hardware.location.gps" android:required="false"/>
The following permissions are defined in the package manifest, and are automatically merged into your app's manifest at build time. You don't need to add them explicitly to your manifest:
android.permission.INTERNET
Used by the API to download map tiles from Google Maps servers.
android.permission.ACCESS_NETWORK_STATE
Allows the API to check the connection status in order to determine whether
data can be downloaded.
Restricting Autocomplete Search to Region #
The Result
s returned can be restricted to certain countries by passing an array of country codes into the components
parameter of MapLocationPicker
. Countries must be two character, ISO 3166-1 Alpha-2
compatible.
You can find code information
at Wikipedia: List of ISO 3166 country codes or
the ISO Online Browsing Platform.
Basic Usage #
import 'package:map_location_picker/map_location_picker.dart';
MapLocationPicker(
config: MapPickerConfig(
apiKey: "YOUR_API_KEY",
initialPosition: LatLng(37.7749, -122.4194),
),
searchConfig: PlacesAutocompleteConfig(
apiKey: "YOUR_API_KEY",
searchHintText: "Search locations...",
),
);
π What's New in 2.0.0 #
1. Cupertino-Style UI #
The entire UI has been redesigned with Cupertino components for a native iOS feel:
PlacesAutocomplete(
config: PlacesAutocompleteConfig(
// Uses CupertinoTypeAheadField internally
searchHintText: "Search locations...",
),
);
2. Theme Support #
Built-in support for light/dark themes with automatic switching:
final _themeMode = ValueNotifier<ThemeMode>(ThemeMode.light);
MapLocationPicker(
config: MapPickerConfig(
// Automatically adapts to current theme
),
);
3. Enhanced Configuration #
More granular control with expanded configuration objects:
MapPickerConfig(
mapTypeButton: CustomMapTypeButton(), // Fully customizable buttons
locationButton: CustomLocationButton(),
bottomCardBuilder: (ctx, result, address, isLoading, onNext) {
return CustomBottomCard(address: address);
},
);
4. Improved Map Previews #
New static map previews for selected locations:
Image.network(
googleStaticMapWithMarker(
_pickedLocation!.latitude,
_pickedLocation!.longitude,
18,
apiKey: YOUR_API_KEY,
),
);
5. Advanced Marker Support #
Custom markers with asset-based icons:
void _createMarkerIcon() async {
_customMarkerIcon = await BitmapDescriptor.asset(
const ImageConfiguration(size: Size(48, 48)),
'assets/marker.webp',
);
}
MapPickerConfig(
mainMarkerIcon: _customMarkerIcon,
);
π Key Features #
Cupertino-Styled Search #
PlacesAutocomplete(
config: PlacesAutocompleteConfig(
searchHintText: "Search locations...",
itemBuilder: (context, prediction) => CupertinoListTile(
title: Text(prediction.description ?? ""),
subtitle: Text(prediction.secondaryText ?? ""),
),
),
);
Theme-Aware Components #
// Automatically adapts to light/dark themes
MapLocationPicker(
config: MapPickerConfig(
floatingControlsColor: Theme.of(context).colorScheme.primary,
floatingControlsIconColor: Theme.of(context).colorScheme.onPrimary,
),
);
Customizable Bottom Sheets #
MapPickerConfig(
bottomCardBuilder: (context, result, address, isLoading, onNext) {
return CupertinoActionSheet(
title: const Text("Selected Location"),
actions: [
CupertinoActionSheetAction(
onPressed: onNext,
child: Text(address),
),
],
);
},
);
Advanced Marker Configuration #
MapPickerConfig(
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),
},
customInfoWindows: const {
"landmark1": InfoWindow(title: "Golden Gate Bridge"),
},
);
π Setup Guide #
API Keys Setup #
- Get an API key at Google Cloud Console
- Enable required APIs:
- Maps SDK for Android/iOS
- Places API
- Geocoding API
- Maps JavaScript API (for web)
Android Setup #
Add to AndroidManifest.xml
:
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="YOUR_ANDROID_API_KEY"/>
iOS Setup #
Add to AppDelegate.swift
:
GMSServices.provideAPIKey("YOUR_IOS_API_KEY")
Web Setup #
Add to web/index.html
:
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_WEB_API_KEY"></script>
π» Example App #
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(
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
themeMode: themeMode,
home: const LocationPickerScreen(),
);
},
);
}
}
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',
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Location Picker')),
body: SingleChildScrollView(
child: Column(
children: [
// Map preview
Container(
height: 200,
child: _pickedLocation == null
? Center(child: Text("Select a location"))
: Image.network(
googleStaticMapWithMarker(
_pickedLocation!.latitude,
_pickedLocation!.longitude,
16,
apiKey: YOUR_API_KEY,
),
fit: BoxFit.cover,
),
),
// Address display
ListTile(
leading: Icon(Icons.location_on),
title: Text(_formattedAddress),
),
// Picker options
_buildOptionCard(
icon: Icons.map,
title: "Standard Picker",
onTap: () => _openPicker(standardConfig),
),
// More options...
],
),
),
);
}
void _openPicker(MapPickerConfig config) async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MapLocationPicker(
config: config.copyWith(
initialPosition: _pickedLocation,
onNext: (result) {
if (result != null) {
setState(() {
_pickedLocation = LatLng(
result.geometry.location.lat,
result.geometry.location.lng,
);
_formattedAddress = result.formattedAddress ?? "";
});
}
},
),
searchConfig: PlacesAutocompleteConfig(
apiKey: YOUR_API_KEY,
),
),
),
);
}
}
π° Support the Project #
π¨βπ» Contribute #
We welcome contributions! Please see our contribution guidelines.