forui_place_picker_google 1.0.2
forui_place_picker_google: ^1.0.2 copied to clipboard
ForUI 0.25 place picker for Google Maps, written in Dart for Flutter.
ForUI Place Picker Google #
A ForUI place picker for the Google Maps APIs, written in Dart for Flutter.
This is a fork of place_picker_google, but added some customizations to adhere to ForUI concepts. One should be able to migrate from place_picker_google to forui_place_picker_google with minimal changes.
Buttons, dialogs, and progress indicators use ForUI. The search field is a ForUI-styled
EditableText (not FTextField). Layout primitives such as Container, Column, and Stack stay on
package:flutter/widgets.dart. The package does not import Material or Cupertino design widgets, so it works with
Flutter's Material/Cupertino decoupling.
You need Places API, Maps SDK for Android, Maps SDK for iOS, and Geocoding API enabled on your API key.
Requires Flutter 3.47+, Dart 3.12+, and ForUI 0.25+.
| Android | iOS | Web | |
|---|---|---|---|
| Support | API 24+ (Flutter 3.47 minSdk) |
iOS 14+ | Same as Flutter |
Screenshots #
Because this uses ForUI, it looks the same on iOS and Android.
![]() |
|---|
Places Autocomplete & Nearby Places #
![]() |
![]() |
|---|
My Location (native and custom) #
![]() |
![]() |
|---|
Getting Started #
-
Get an API key at https://cloud.google.com/maps-platform/.
-
Enable Google Map SDK for each platform.
- Go to Google Developers Console.
- Choose the project that you want to enable Google Maps on.
- Select the navigation menu and then select "Google Maps".
- Select "APIs" under the Google Maps menu.
- To enable Google Maps for Android, select "Maps SDK for Android" in the "Additional APIs" section, then select "ENABLE".
- To enable Google Maps for iOS, select "Maps SDK for iOS" in the "Additional APIs" section, then select "ENABLE".
- To enable Google Maps for Web, enable the "Maps JavaScript API".
- Make sure the APIs you enabled are under the "Enabled APIs" section.
-
You can also find detailed steps to get started with Google Maps Platform here.
Android #
Flutter 3.47 apps use Kotlin DSL Gradle. Configure the app in android/app/build.gradle.kts.
google_maps_flutter needs Android API 24+. Flutter 3.47 already defaults minSdk to 24 via flutter.minSdkVersion, so a new project is fine as-is. If you override it, keep it at 24 or higher:
android {
defaultConfig {
minSdk = flutter.minSdkVersion // 24 on Flutter 3.47
// or: minSdk = 24
}
}
Android builds on Flutter 3.47 require Java 17.
Then add your API key in android/app/src/main/AndroidManifest.xml:
<manifest ...
<application ...
<!-- TODO: Add your Google Maps API key here -->
<meta-data android:name="com.google.android.geo.API_KEY"
android:value="YOUR ANDROID KEY HERE"/>
<activity ..../>
</application>
</manifest>
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.
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
iOS #
google_maps_flutter supports iOS 14+. New Flutter apps use Swift. Add your API key in ios/Runner/AppDelegate.swift:
import Flutter
import GoogleMaps
import UIKit
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// TODO: Add your Google Maps API key
GMSServices.provideAPIKey("YOUR KEY HERE")
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
Note #
On iOS you'll need to add the following entries to your Info.plist file (located under ios/Runner) in order to access the device's location.
Simply open your Info.plist file and add the following:
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to location when open.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This app needs access to location when in the background.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app needs access to location when open and in the background.</string>
Web #
You'll need to modify the web/index.html file of your Flutter Web application to include the Google Maps JS SDK.
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 -->
<!-- TODO: Add your Google Maps API key -->
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"></script>
</head>
Check the google_maps_flutter_web README
for the latest information on how to prepare your App to use Google Maps on the
web.
Note #
-
Browser-based apps can't use
dart:iolibrary for thePlatformAPI. Only servers, command-line scripts, and Flutter mobile apps can import and usedart:io.A native solution to switch between the platforms would be to use the
flutter/foundationlibrary.
import 'package:flutter/foundation.dart';
if (kIsWeb) {
/// Web specific code
}
else if (defaultTargetPlatform == TargetPlatform.iOS || defaultTargetPlatform == TargetPlatform.android) {
/// Android/iOS specific code
}
- Google places API prevents
CORS. So we can't make a request from client-side. And As the PlacesAutocomplete widget makes http request to the Google places API like this:
"https://maps.googleapis.com/maps/api/place/autocomplete/json?input=${Search-Query}&key=${API-Key}"
This client-side request will be prevented. The Google API was not made to be call from browser. You need to use a proxy server that add the CORS to your request. e.g cors-anywhere.
Deploy the proxy server in Heroku or Vercel. You'll get a URL after deployment. After that you need to add the URL before your API endpoint while making the calls. i.e "proxy_server_url/google_api_endpoint". The proxy server will add the necessary headers.
For example with the proxy server it would look like
"https://cors-anywhere.herokuapp.com/https://maps.googleapis.com/maps/api/place/autocomplete/json?input=${Search-Query}&key=${API-Key}"
Therefore set the web baseUrl as
"https://cors-anywhere.herokuapp.com/https://maps.googleapis.com/maps/api/"
Setup #
Add this to your package's pubspec.yaml file:
dependencies:
forui: ^0.25.0
forui_place_picker_google: ^1.0.0
Wrap the app in FTheme. WidgetsApp is enough; you do not need MaterialApp or CupertinoApp.
import 'package:flutter/widgets.dart';
import 'package:forui/forui.dart';
import 'package:forui_place_picker_google/forui_place_picker_google.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return WidgetsApp(
color: const Color(0xFF171717),
localizationsDelegates: FLocalizations.localizationsDelegates,
supportedLocales: FLocalizations.supportedLocales,
pageRouteBuilder: <T>(settings, builder) {
return PageRouteBuilder<T>(
settings: settings,
pageBuilder: (context, animation, secondaryAnimation) =>
builder(context),
);
},
builder: (context, child) => FTheme(
data: FTheme.neutral.light.touch,
child: child ?? const SizedBox.shrink(),
),
home: const Placeholder(),
);
}
}
Import the picker:
import 'package:forui_place_picker_google/forui_place_picker_google.dart';
Basic usage #
Push PlacePicker with Navigator, or place it as a child. When the user confirms a place, onPlacePicked receives a
LocationResult. To replace the bottom panel, pass selectedPlaceWidgetBuilder (that path does not call
onPlacePicked).
PlacePicker(
apiKey: Platform.isAndroid
? 'GOOGLE_MAPS_API_KEY_ANDROID'
: 'GOOGLE_MAPS_API_KEY_IOS',
onPlacePicked: (LocationResult result) {
debugPrint('Place picked: ${result.formattedAddress}');
},
initialLocation: const LatLng(29.378586, 47.990341),
showSearchInput: true,
myLocationEnabled: true,
myLocationButtonEnabled: true,
searchInputConfig: const SearchInputConfig(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
autofocus: false,
textDirection: TextDirection.ltr,
),
searchInputDecorationConfig: const SearchInputDecorationConfig(
hintText: 'Search for a building, street or ...',
),
selectedPlaceConfig: const SelectedPlaceConfig.init(
actionButtonText: 'Confirm Location',
),
)
Navigate without MaterialPageRoute:
Navigator.of(context).push(
PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) => PlacePicker(
apiKey: apiKey,
onPlacePicked: (result) => Navigator.of(context).pop(result),
),
),
);
Common PlacePicker parameters #
| Parameter | Purpose |
|---|---|
apiKey |
Google Maps / Places API key |
onPlacePicked |
Called when the user confirms a place |
initialLocation |
Camera start position (skips panning to GPS if set) |
showSearchInput |
Show the search field |
enableNearbyPlaces |
Load Nearby Search results |
usePinPointingSearch |
Reverse-geocode when the map camera settles |
useFreeGeocoding |
Use on-device geocoding instead of Google Geocoding API |
myLocationEnabled / myLocationButtonEnabled |
GPS layer and locate button |
searchInputConfig / searchInputDecorationConfig |
Search field behavior and look |
selectedPlaceConfig |
Confirm panel text and FButton style |
selectedPlaceWidgetBuilder |
Replace the confirm panel (skips onPlacePicked) |
mapsBaseUrl |
Override the Maps HTTP base URL (needed for web CORS proxies) |
ForUI styling #
Controls use ForUI. Layout stays on package:flutter/widgets.dart.
| Surface | Widget |
|---|---|
| Confirm action | FButton |
| My location | FButton.icon |
| Location permission prompt | FDialog |
| Loading | FCircularProgress |
| Search field | ForUI-styled EditableText (not FTextField) |
The search field follows FTextField colors, padding, and typography through FTextFieldStyleDelta. It does not use
FTextField itself, because ForUI wraps that control in MergeSemantics, which asserts on Flutter 3.47 when the field
is focused next to a Google Map platform view.
| Config | ForUI types |
|---|---|
SearchInputDecorationConfig |
Labels, hints, icons, and FTextFieldStyleDelta |
SelectedPlaceConfig.actionButtonStyle |
FButtonStyleDelta |
MyLocationFABConfig.style |
FButtonStyleDelta for the locate button |
Material InputBorder, ButtonStyle, Theme.of, and Icons.* are not used. Use ForUI tokens from context.theme
(for example context.theme.colors.background) when you customize builders.
Example:
PlacePicker(
...
myLocationFABConfig: MyLocationFABConfig(
style: .delta(
decoration: .delta([
.all(.boxDelta(color: context.theme.colors.secondary)),
]),
iconContentStyle: .delta(
iconStyle: .delta([
.all(.delta(color: context.theme.colors.secondaryForeground)),
]),
),
),
),
...
)
Enabling nearby searches #
Set enableNearbyPlaces: true to load Google Places Nearby Search results for the selected location.
Customizing selected place UI #
By default, when a user selects a place from autocomplete or by dragging/tapping the map, the picker shows name, address, and a confirm button at the bottom.
Override that panel with selectedPlaceWidgetBuilder.
Using selectedPlaceWidgetBuilder skips onPlacePicked. Handle confirmation in your builder.
Free geocoding (reduce Google API billing) #
This package can reverse-geocode with the geocoding plugin, which uses on-device services on iOS and Android.
Set useFreeGeocoding: true on PlacePicker.
Benefits #
- Avoids Google Geocoding API calls → Reduce billing costs
- On-device geocoding for common address lookups
- Works offline for some platforms (cached or approximated results)
Note: #
- Native geocoding may provide less detailed results than Google Geocoding API.
- For precise or international addresses, use Google’s API as a fallback.
- Not available on the web.
Packages Used #
Below are the information about the packages used.
| PACKAGE | INFO |
|---|---|
| forui | Buttons, dialogs, progress, and theme |
| http | To consume HTTP resources |
| geolocator | Access to location services |
| google_maps_flutter | Access to Google Maps widget |
| geocoding | Access to free Geocoding services |
Feature Requests and Issues #
Please file feature requests and bugs at the issue tracker.
Contribute #
Issues and PRs welcome. Unless otherwise specified, all contributions to this lib will be under MIT license.




