google_maps_place_picker 0.9.1

  • Readme
  • Changelog
  • Example
  • Installing
  • 94

Google Maps Place Picker #

A Flutter plugin which provides 'Picking Place' using Google Maps widget.

The project relies on below packages.

Map using Flutter's official google_maps_flutter
Fetching current location using Baseflow's geolocator
Place and Geocoding API using hadrienlejard's google_maps_webservice
Builder using kevmoo's tuple

Preview #

Support #

If the package was useful or saved your time, please do not hesitate to buy me a cup of coffee! ;)
The more caffeine I get, the more useful projects I can make in the future.

Buy Me A Coffee

Getting Started #

Get an API key at https://cloud.google.com/maps-platform/.

Android #

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"/>

NOTE: As of version 3.0.0 the geolocator plugin switched to the AndroidX version of the Android Support Libraries. This means you need to make sure your Android project is also upgraded to support AndroidX. Detailed instructions can be found here.

The TL;DR version is:

  1. Add the following to your "gradle.properties" file:
android.useAndroidX=true
android.enableJetifier=true
  1. Make sure you set the compileSdkVersion in your "android/app/build.gradle" file to 28:
android {
 compileSdkVersion 28

 ...
}
  1. Make sure you replace all the android. dependencies to their AndroidX counterparts (a full list can be found here: https://developer.android.com/jetpack/androidx/migrate).

iOS #

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: [UIApplicationLaunchOptionsKey: Any]?
  ) -> Bool {
    GMSServices.provideAPIKey("YOUR KEY HERE")
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

Opt-in to the embedded views preview by adding a boolean property to the app's Info.plist file with the key io.flutter.embedded_views_preview and the value YES.

Usage #

Basic usage #

You can use PlacePicker by pushing to a new page using Navigator. When the user picks a place on the map, it will return result to 'onPlacePicked' with PickResult type. Alternatively, you can build your own way with 'selectedPlaceWidgetBuilder' and fetch result from it (See the instruction below).

Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => PlacePicker(
          apiKey: APIKeys.apiKey,   // Put YOUR OWN KEY here.
          onPlacePicked: (result) { 
            print(result.address); 
            Navigator.of(context).pop();
          },
          initialPosition: HomePage.kInitialPosition,
          useCurrentLocation: true,
        ),
      ),
    );

PickResult

ParameterTypeDescription
placeIdStringA textual identifier that uniquely identifies a place. To retrieve information about the place, pass this identifier in the placeId field of a Places API request. See PlaceId for more information.
geometryGeometryContains geometry information about the result, generally including the location (geocode) of the place and (optionally) the viewport identifying its general area of coverage.
formattedAddressStringA string containing the human-readable address of this place. Often this address is equivalent to the "postal address".
typesList<String>Contains an array of feature types describing the given result. See the list of supported types. XML responses include multiple
addressComponentsList<AddressComponent>An array containing the separate components applicable to this address.

** Below results will be fetched only when using auto-complete search or usePlaceDetailSearch is set to true when searching by dragging the map.

PickResult (Optional)

ParameterTypeDescription
adrAddressStringA representation of the place's address in the adr microformat
formattedPhoneNumberStringContains the place's phone number in its local format
idString? (Not documented at Google - see more info below)
referenceString? (Not documented at Google - see more info below)
iconStringThe URL of a suggested icon which may be displayed to the user when indicating this result on a map.
nameStringHuman-readable name for the returned result
openingHoursOpeningHoursDetailOpening hour information
photosList<Photo>Array of photo objects, each containing a reference to an image
internationalPhoneNumberStringThe place's phone number in international format
priceLevelPriceLevelThe price level of the place, on a scale of 0 to 4. The exact amount indicated by a specific value will vary from region to region.
ratingnumThe place's rating, from 1.0 to 5.0, based on aggregated user reviews.
scopeString
urlStringThe URL of the official Google page for this place.
vicinityStringLists a simplified address for the place, including the street name, street number, and locality, but not the province/state, postal code, or country
utcOffsetnumThe number of minutes this place’s current timezone is offset from UTC
websiteStringThe authoritative website for this place
reviewsList<Review>JSON array of up to five reviews

More info about results at Google document.

PlacePicker

ParameterTypeDescription
apiKeyString(Required) Your google map API Key
onPlacePickedCallback(PickResult)Invoked when user picks the place and selects to use it. This will not be called if you manually build 'selectedPlaceWidgetBuilder' as you will override default 'Select here' button.
initialPositionLatLng(Required) Initial center position of google map when it is created. If useCurrentLocation is set to true, it will try to get device's current location first using GeoLocator.
useCurrentLocationboolWhether to use device's current location for initial center position. This will be used instead of initial position when it is set to true AND user ALLOW to collect their location. If DENIED, initialPosition will be used.
desiredLocationAccuracyLocationAccuracyAccuracy of fetching current location. Defaults to 'high'.
hintTextStringHint text of search bar
searchingTextStringA text which appears when searching is performing. Default to 'Searching...'
proxyBaseUrlStringUsed for API calling on google maps. In case of using a proxy the baseUrl can be set. The apiKey is not required in case the proxy sets it.
httpClientClientUsed for API calling on google maps. In case of using a proxy url that requires authentication or custom configuration.
autoCompleteDebounceInMillisecondsintDebounce timer for auto complete input. Default to 500
cameraMoveDebounceInMillisecondsintDebounce timer for searching place with camera(map) dragging. Defaults to 750
intialMapTypeMapTypeMapTypes of google map. Defaults to normal.
enableMapTypeButtonboolWhether to display MapType change button on the map
enableMyLocationButtonboolWhether to display my location button on the map
usePinPointingSearchboolDefaults to true. This will allow user to drag map and get a place info where the pin is pointing.
usePlaceDetailSearchboolDefaults to false. Setting this to true will get detailed result from searching by dragging the map, but will use +1 request on Place Detail API.
onAutoCompleteFailedCallback(String)Invoked when auto complete search is failed
onGeocodingSearchFailedCallback(String)Invoked when searching place by dragging the map failed
onMapCreatedMapCreatedCallbackReturens google map controller when created
selectedPlaceWidgetBuilderWidgetBuilderSpecified on below section
pinBuilderWidgetBuilderSpecified on below section
autocompleteOffsetnumThe position, in the input term, of the last character that the service uses to match predictions
autocompleteRadiusnumThe distance (in meters) within which to return place results
autocompleteLanguageStringThe language code, indicating in which language the results should be returned, if possible.
autocompleteComponentsList<Components>A grouping of places to which you would like to restrict your results. Currently, you can use components to filter by up to 5 countries.
autocompleteTypesList<String>The types of place results to return. See Place Types.
strictboundsboolReturns only those places that are strictly within the region defined by location and radius.
regionStringregion — The region code, specified as a ccTLD (country code top-level domain) two-character value. Most ccTLD codes are identical to ISO 3166-1 codes, with some exceptions. This parameter will only influence, not fully restrict, search results. If more relevant results exist outside of the specified region, they may be included. When this parameter is used, the country name is omitted from the resulting formatted_address for results in the specified region.
selectInitialPositionboolWhether to display selected place on initial map load. Defaults to false.
resizeToAvoidBottomInsetboolRefer to Scaffold's resizeToAvoidBottomInset property.
initialSearchStringStringSets initial search string for auto complete search
searchForInitialValueboolWether to automatically search for initial value on start
forceAndroidLocationManagerboolOn Android devices you can set this to true to force the geolocator plugin to use the 'LocationManager' to determine the position instead of the 'FusedLocationProviderClient'. On iOS this is ignored.
myLocationButtonCooldownintCooldown time in seconds for the 'myLocationButton'. Defaults to 10 seconds.
forceSearchOnZoomChangedboolWether to allow place search even when the zoom has changed. Defaults to false.

More info about autocomplete search at Google document.

Customizing picked place visualisation #

By default, when a user picks a place by using auto complete search or dragging the map, we display the information at the bottom of the screen (FloatingCard).

However, if you don't like this UI/UX, simply override the builder using 'selectedPlaceWidgetBuilder'. FlocatingCard widget can be reused which is floating around the screen or build an entirely new widget as you want. It is stacked with the map, so you might want to use the Positioned widget.

Note that using this customization WILL NOT INVOKE [onPlacePicked] callback as it will override default 'Select here' button on floating card

...
PlacePicker(apiKey: APIKeys.apiKey,
            ...
            selectedPlaceWidgetBuilder: (_, selectedPlace, state, isSearchBarFocused) {
              return isSearchBarFocused
                  ? Container()
                  // Use FloatingCard or just create your own Widget.
                  : FloatingCard(
                      bottomPosition: MediaQuery.of(context).size.height * 0.05,
                      leftPosition: MediaQuery.of(context).size.width * 0.05,
                      width: MediaQuery.of(context).size.width * 0.9,
                      borderRadius: BorderRadius.circular(12.0),
                      child: state == SearchingState.Searching ? 
                                      Center(child: CircularProgressIndicator()) : 
                                      RaisedButton(onPressed: () { print("do something with [selectedPlace] data"); },),
                   );
            },
            ...
          ),
...
ParametersTypeDescription
contextBuildContextFlutter's build context value
selectedPlacePickResultResult data of user selected place
stateSearchingStateState of searching action. (Idle, Searching)
isSearchBarFocusedboolWhether the search bar is currently focused so the keyboard is shown

Customizing Pin #

By default, Pin icon is provided with very simple picking animation when moving around.
However, you can also create your own pin widget using 'pinBuilder'

PlacePicker(apiKey: APIKeys.apiKey,
            ...
            pinBuilder: (context, state) {
                  if (state == PinState.Idle) {
                    return Icon(Icons.favorite_border);
                  } else {
                    return AnimatedIcon(.....);
                  }
                },
            ...                        
          ),
...
ParametersTypeDescription
contextBuildContextFlutter's build context value
statePinStateState of pin. (Preparing; When map loading, Idle, Dragging)

Changing Colours of default FloatingCard #

While you can build your own prediction tile, you still can change the style of default tile using themeData as below:

// Light Theme
final ThemeData lightTheme = ThemeData.light().copyWith(
  // Background color of the FloatingCard
  cardColor: Colors.white,
  buttonTheme: ButtonThemeData(
    // Select here's button color
    buttonColor: Colors.black,
    textTheme: ButtonTextTheme.primary,
  ),
);

// Dark Theme
final ThemeData darkTheme = ThemeData.dark().copyWith(
  // Background color of the FloatingCard
  cardColor: Colors.grey,
  buttonTheme: ButtonThemeData(
    // Select here's button color
    buttonColor: Colors.yellow,
    textTheme: ButtonTextTheme.primary,
  ),
);

Feature Requests and Issues #

Please file feature requests and bugs at the issue tracker.

Other useful packages you might be insterested #

Firebase Auth Simplify
Material design Speed Dial

Buy Me A Coffee

[0.9.1] - 10/Mar/2020 #

  • Added [forceSearchOnZoomChanged] parameter to allow place search even when the zoom has changed. Issue #21

[0.9.0] - 10/Mar/2020 #

  • Hot fix. DO NOT use 0.8.1 anymore.
  • Fixed bug that auto complete search prediction layout is not displaying.

[0.8.1] - 10/Mar/2020 #

  • Added location service checking logic when using [useCurrentLocation].
  • Added [forceAndroidLocationManager] parameter for GeoLocator package.
  • Updated GeoLocator version to 5.3.0.
  • Bug Fixed. Changing orientation of the device will not break UI of search prediction anymore. Issue #15

[0.8.0] - 07/Mar/2020 #

  • New feature. You can now set [initialSearchString] and [searchForInitialValue]. Issue(Pull Request) #14 (@moritzdouda)
  • Bug Fixed. Changing orientation of the device will not break UI of Floating card anymore. Issue #15

[0.7.1] - 06/Mar/2020 #

  • Bug Fixed. [autoCompleteLanguage] will now display the correct result.

[0.7.0] - 25/Feb/2020 #

  • Bug Fixed. Fixed throwing rendering exception when [useCurrentLocation] is set to false. Issue #11.
  • [initialPosition] has been set to Required paramater since Google Map needs at least one initial position of the camera. Issue #10.

[0.6.4] - 22/Feb/2020 #

  • Feature added. You can set resizeToAvoidBottomInset for the scaffold to avoid resizing screen when keyboard is shown.
  • Example modified. Removed MediaQuery.of(context) from the example as it will cause rebuild.

[0.6.3] - 20/Feb/2020 #

  • Feature added. Now, initial position of the map can be 'selected' automatically.

[0.6.2] - 17/Feb/2020 #

  • Fixed bug. Map icons are now positioned correctly.
  • Fixed iOS obsoleted in swift 4.2 issue for the example.

[0.6.1] - 6/Feb/2020 #

  • Added region option for auto-complete search.
  • Updated README.md for added parameters.

[0.6.0] - 5/Feb/2020 #

  • Added options for auto-complete search. Now you can narrow down the result using offset, radius, language, types, components and strictbounds.
  • Updated README.md for added parameters.

[0.5.1] - 3/Feb/2020 #

  • Minor bug Fix.

[0.5.0] - 31/Jan/2020 #

  • Added 'usePinPointingSearch' option. Setting it to false will not allow user to get a place info with map dragging. Defaults to true.
  • Added 'usePlaceDetailSearch' option. Setting this to true will get detailed result from searching by dragging the map, but will use +1 request on Place Detail API. Defaults to false.
  • Fixed bug of not returning Searching state to 'selectedPlaceWidgetBuilder'.
  • Fixed bug of unnecessary search (issue #4). No extra searching will be performed from now when camera is moved by auto-complete search.

[0.4.0] - 29/Jan/2020 #

  • Fixed bug that autoComplete search prediction is remaining on screen when poping from map page. (Issue #3)
  • Search bar no longer relies on appBarRenderBox height. Position is fixed to 86 on top.
  • Added example for changing colour
  • AutoComplete search prediction's title colour now relies on Theme.of(context).textTheme.title.color

[0.3.0] - 27/Jan/2020 #

  • The colors of FloatingCard (Prediction tile on the map) can be controlled by Theme Data.
  • Fixed back button for iOS (StanfordLin).
  • Pin color will be default to [Red] from now. You can still customize your pin using pinBuilder if you don't like default style ;).

[0.2.2] - 24/Jan/2020 #

  • Updated example to apply changed function

[0.2.1] - 24/Jan/2020 #

  • Updated README for more information about result callback

[0.2.0] - 24/Jan/2020 #

  • Added onResult callback. Now we can listen for the callback to get the result instead of using Navigator callback.

[0.1.4] - 23/Jan/2020 #

  • Updated additional information regarding 'PickResult' data
  • Fixed typo

[0.1.3] - 23/Jan/2020 #

  • Updated additional information regarding 'geolocator' settings

[0.1.2] - 23/Jan/2020 #

  • flutter format for suggested files

[0.1.1] - 23/Jan/2020 #

  • flutter format for suggested files
  • Re-write package description

[0.1.0] - 23/Jan/2020 #

  • Update parameter info
  • Map buttons added

[0.0.3] - 22/Jan/2020 #

  • Added function. Picking place by dragging camera
  • Bug fix: minor
  • Fix typo

[0.0.2] - 20/Jan/2020 #

  • Refactoring

[0.0.1] - 19/Jan/2020 #

  • Initial release

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:google_maps_place_picker/google_maps_place_picker.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

// Your api key storage.
import 'keys.dart';

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

class MyApp extends StatelessWidget {
  // Light Theme
  final ThemeData lightTheme = ThemeData.light().copyWith(
    // Background color of the FloatingCard
    cardColor: Colors.white,
    buttonTheme: ButtonThemeData(
      // Select here's button color
      buttonColor: Colors.black,
      textTheme: ButtonTextTheme.primary,
    ),
  );

  // Dark Theme
  final ThemeData darkTheme = ThemeData.dark().copyWith(
    // Background color of the FloatingCard
    cardColor: Colors.grey,
    buttonTheme: ButtonThemeData(
      // Select here's button color
      buttonColor: Colors.yellow,
      textTheme: ButtonTextTheme.primary,
    ),
  );

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Google Map Place Picker Demo',
      theme: lightTheme,
      darkTheme: darkTheme,
      themeMode: ThemeMode.light,
      home: HomePage(),
      debugShowCheckedModeBanner: false,
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({Key key}) : super(key: key);

  static final kInitialPosition = LatLng(-33.8567844, 151.213108);

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  PickResult selectedPlace;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Google Map Place Picer Demo"),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              RaisedButton(
                child: Text("Load Google Map"),
                onPressed: () {
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (context) {
                        return PlacePicker(
                          apiKey: APIKeys.apiKey,
                          initialPosition: HomePage.kInitialPosition,
                          useCurrentLocation: true,
                          //usePlaceDetailSearch: true,
                          onPlacePicked: (result) {
                            selectedPlace = result;
                            Navigator.of(context).pop();
                            setState(() {});
                          },
                          forceSearchOnZoomChanged: true,
                          //autocompleteLanguage: "ko",
                          //region: 'au',
                          //selectInitialPosition: true,
                          // selectedPlaceWidgetBuilder: (_, selectedPlace, state, isSearchBarFocused) {
                          //   print("state: $state, isSearchBarFocused: $isSearchBarFocused");
                          //   return isSearchBarFocused
                          //       ? Container()
                          //       : FloatingCard(
                          //           bottomPosition: 0.0,    // MediaQuery.of(context) will cause rebuild. See MediaQuery document for the information.
                          //           leftPosition: 0.0,
                          //           rightPosition: 0.0,
                          //           width: 500,
                          //           borderRadius: BorderRadius.circular(12.0),
                          //           child: state == SearchingState.Searching
                          //               ? Center(child: CircularProgressIndicator())
                          //               : RaisedButton(
                          //                   child: Text("Pick Here"),
                          //                   onPressed: () {
                          //                     // IMPORTANT: You MUST manage selectedPlace data yourself as using this build will not invoke onPlacePicker as
                          //                     //            this will override default 'Select here' Button.
                          //                     print("do something with [selectedPlace] data");
                          //                     Navigator.of(context).pop();
                          //                   },
                          //                 ),
                          //         );
                          // },
                          // pinBuilder: (context, state) {
                          //   if (state == PinState.Idle) {
                          //     return Icon(Icons.favorite_border);
                          //   } else {
                          //     return Icon(Icons.favorite);
                          //   }
                          // },
                        );
                      },
                    ),
                  );
                },
              ),
              selectedPlace == null ? Container() : Text(selectedPlace.formattedAddress ?? ""),
            ],
          ),
        ));
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  google_maps_place_picker: ^0.9.1

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:google_maps_place_picker/google_maps_place_picker.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
88
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
94
Learn more about scoring.

We analyzed this package on Apr 7, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.7.1
  • pana: 0.13.6
  • Flutter: 1.12.13+hotfix.8

Health suggestions

Fix lib/providers/place_provider.dart. (-0.50 points)

Analysis of lib/providers/place_provider.dart reported 1 hint:

line 12 col 8: Unused import: 'package:flutter/services.dart'.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0 <3.0.0
flutter 0.0.0
geolocator ^5.3.0 5.3.1
google_maps_flutter ^0.5.21+15 0.5.25+3
google_maps_webservice ^0.0.16 0.0.16
http ^0.12.0+4 0.12.0+4
provider ^4.0.1 4.0.4 4.1.0-dev+2
tuple ^1.0.3 1.0.3
Transitive dependencies
async 2.4.1
charcode 1.1.3
collection 1.14.11 1.14.12
equatable 1.1.1
flutter_plugin_android_lifecycle 1.0.6
google_api_availability 2.0.4
http_parser 3.1.4
location_permissions 2.0.5
matcher 0.12.6
meta 1.1.8
nested 0.0.4
path 1.6.4
pedantic 1.9.0
quiver 2.1.3
sky_engine 0.0.99
source_span 1.7.0
stack_trace 1.9.3
string_scanner 1.0.5
term_glyph 1.1.0
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test