Google Maps Place Picker

一个 Flutter 插件,它使用 Google Maps 小部件提供“地点选取”。

项目依赖以下包。

使用 Flutter 官方 google_maps_flutter 进行地图显示,使用 Baseflow 的 geolocator 获取当前位置,使用 hadrienlejard 的 google_maps_webservice 进行地点和地理编码 API 调用,使用 kevmoo 的 tuple 进行构建。

预览

支持

如果该插件对您有帮助或节省了您的时间,请随时给我买杯咖啡!? 我得到的咖啡越多,将来就能做出越多有用的项目。

Buy Me A Coffee

入门

  • https://cloud.google.com/maps-platform/ 获取 API 密钥。

  • 为每个平台启用 Google Map SDK。

    • 前往 Google Developers Console
    • 选择您要启用 Google Maps 的项目。
    • 选择导航菜单,然后选择“Google Maps”。
    • 在 Google Maps 菜单下选择“API”。
    • 要为 Android 启用 Google Maps,请在“其他 API”部分选择“Maps SDK for Android”,然后选择“ENABLE”。
    • 要为 iOS 启用 Google Maps,请在“其他 API”部分选择“Maps SDK for iOS”,然后选择“ENABLE”。
    • 确保您启用的 API 位于“已启用 API”部分。
  • 您还可以 此处 找到开始使用 Google Maps Platform 的详细步骤。

Android

在 `android/app/src/main/AndroidManifest.xml` 应用程序清单中指定您的 API 密钥

<manifest ...
  <application ...
    <meta-data android:name="com.google.android.geo.API_KEY"
               android:value="YOUR KEY HERE"/>

注意: 从 3.0.0 版本开始,geolocator 插件切换到了 AndroidX 版本的 Android Support Libraries。这意味着您需要确保您的 Android 项目也已升级以支持 AndroidX。详细说明可以在 此处 找到。

简而言之就是

  1. 将以下内容添加到您的“gradle.properties”文件中

android.useAndroidX=true
android.enableJetifier=true
  1. 确保您的 `android/app/build.gradle` 文件中的 `compileSdkVersion` 设置为 28

android {
 compileSdkVersion 28

 ...
}
  1. 确保您将所有 `android.` 依赖项替换为其 AndroidX 对应项(完整列表可以在这里找到:https://developer.android.com.cn/jetpack/androidx/migrate)。

iOS

在应用程序委托 `ios/Runner/AppDelegate.m` 中指定您的 API 密钥

#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

或者在您的 Swift 代码中,在应用程序委托 `ios/Runner/AppDelegate.swift` 中指定您的 API 密钥

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)
  }
}

在 iOS 上,您需要在 Info.plist 文件(位于 `ios/Runner` 下)中添加以下条目,以便访问设备的地理位置。

只需打开您的 Info.plist 文件并添加以下内容

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

此外,您需要为您的 XCode 项目添加 `Background Modes` 功能(Project > Signing and Capabilties > “+ Capability” 按钮),然后选择 `Location Updates`。g>此应用需要在打开和后台运行时访问位置。

通过在应用的 `Info.plist` 文件中添加一个布尔属性 `io.flutter.embedded_views_preview` 并将其值设置为 `YES` 来选择加入嵌入式视图预览。

<key>io.flutter.embedded_views_preview</key>
<true/>

用法

基本用法

您可以通过 Navigator 跳转到一个新页面来使用 PlacePicker,或者将其作为任何小部件的子项。当用户在地图上选择一个地点时,它将以 PickResult 类型返回结果到 ‘onPlacePicked’。或者,您可以通过 ‘selectedPlaceWidgetBuilder’ 构建自己的方式并从中获取结果(请参阅下面的说明)。

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

参数 类型 描述
placeId 字符串 一个文本标识符,唯一地标识一个地点。要检索有关该地点的更多信息,请在 Places API 请求的 placeId 字段中传递此标识符。有关更多信息,请参阅 PlaceId
geometry 几何信息 包含有关结果的几何信息,通常包括地点的位置(地理编码)以及(可选)标识其大致覆盖区域的视口。
formattedAddress 字符串 一个包含此地点人类可读地址的字符串。此地址通常等同于“邮寄地址”。
types List<String> 包含描述给定结果的功能类型数组。请参阅 支持的类型列表。XML 响应包含多个元素,如果结果分配了多种类型。
addressComponents List<AddressComponent> 一个包含适用于此地址的单独组件的数组。

** 仅当使用自动完成搜索或在通过拖动地图搜索时将 usePlaceDetailSearch 设置为 true 时,才会获取以下结果。

PickResult (可选)

参数 类型 描述
adrAddress 字符串 地点地址在 adr microformat 中的表示
formattedPhoneNumber 字符串 包含该地点电话号码的 本地格式
id 字符串 ? (未在 Google 文档中记录 – 更多信息请见下方)
reference 字符串 ? (未在 Google 文档中记录 – 更多信息请见下方)
icon 字符串 建议图标的 URL,在地图上指示此结果时可能会显示给用户。
名称 字符串 返回结果的易读名称
openingHours OpeningHoursDetail 营业时间信息
photos List<Photo> 照片对象数组,每个对象包含一个图像引用
internationalPhoneNumber 字符串 该地点电话号码的国际格式
priceLevel PriceLevel 该地点价格水平,范围从 0 到 4。特定值表示的确切金额因地区而异。
rating num 该地点评分,从 1.0 到 5.0,基于聚合用户评论。
scope 字符串
url 字符串 该地点官方 Google 页面的 URL。
vicinity 字符串 列出了该地点的简化地址,包括街道名称、门牌号码和地区,但不包括省/州、邮政编码或国家/地区
utcOffset num 该地点当前时区与 UTC 的偏移量(以分钟为单位)
website 字符串 该地点的权威网站
reviews List<Review> 最多五条评论的 JSON 数组

有关 Google 文档中结果的更多信息

PlacePicker

参数 类型 描述
apiKey 字符串 (必需) 您的 Google Maps API 密钥
onPlacePicked Callback(PickResult) 当用户选择地点并选择使用它时调用。如果您手动构建 ‘selectedPlaceWidgetBuilder’,则不会调用此函数,因为您将覆盖默认的“选择此处”按钮。
initialPosition LatLng (必需) 创建 Google Maps 时地图的初始中心位置。如果将 useCurrentLocation 设置为 true,它将尝试首先使用 GeoLocator 获取设备的当前位置。
useCurrentLocation 布尔值 是否使用设备的当前位置作为初始中心位置。如果设置为 true 并且用户允许收集其位置,则将使用此选项代替 initial position。如果被拒绝,将使用 initialPosition。
desiredLocationAccuracy LocationAccuracy 获取当前位置的精度。默认为“high”。
hintText 字符串 搜索栏的提示文本
searchingText 字符串 搜索进行时显示的文本。默认为“正在搜索…”
proxyBaseUrl 字符串 用于 Google Maps 上的 API 调用。如果使用代理,可以设置 baseUrl。如果代理设置了 apiKey,则不需要 apiKey。
httpClient Client 用于 Google Maps 上的 API 调用。如果使用需要身份验证或自定义配置的代理 URL。
autoCompleteDebounceInMilliseconds 整数 自动完成输入的防抖计时器。默认为 500 毫秒。
cameraMoveDebounceInMilliseconds 整数 通过拖动相机(地图)搜索地点的防抖计时器。默认为 750 毫秒。
intialMapType MapType Google Maps 的地图类型。默认为 normal。
enableMapTypeButton 布尔值 是否在地图上显示地图类型更改按钮
enableMyLocationButton 布尔值 是否在地图上显示我的位置按钮
usePinPointingSearch 布尔值 默认为 true。这将允许用户拖动地图并在图钉指向的位置获取地点信息。
usePlaceDetailSearch 布尔值 默认为 false。将其设置为 true 将从拖动地图搜索中获取详细结果,但会使用 Place Detail API 的额外请求。
onAutoCompleteFailed Callback(String) 自动完成搜索失败时调用
onGeocodingSearchFailed Callback(String) 通过拖动地图搜索地点失败时调用
onMapCreated MapCreatedCallback 创建时返回 Google Maps 控制器
selectedPlaceWidgetBuilder WidgetBuilder 在下面的部分指定
pinBuilder WidgetBuilder 在下面的部分指定
autocompleteOffset num 服务用于匹配预测的输入项中最后一个字符的位置
autocompleteRadius num 用于返回地点结果的距离(以米为单位)
autocompleteLanguage 字符串 语言代码,表示结果应以哪种语言返回(如果可能)。请参阅 语言支持
autocompleteComponents List<Components> 您希望将结果限制在其中的地点分组。目前,您可以使用组件按最多 5 个国家/地区进行筛选。
autocompleteTypes List<String> 要返回的地点结果类型。请参阅 地点类型
strictbounds 布尔值 仅返回严格位于 location 和 radius 定义的区域内的地点。
region 字符串 region — 区域代码,指定为 ccTLD(国家代码顶级域名)两位字符值。大多数 ccTLD 代码与 ISO 3166-1 代码相同,但也有一些例外。此参数只会影响搜索结果,而不会完全限制搜索结果。如果指定区域外存在更相关的结果,它们可能会被包含在内。使用此参数时,指定区域内的结果将省略国家/地区名称。
selectInitialPosition 布尔值 是否在初始地图加载时显示选定的地点。默认为 false。
resizeToAvoidBottomInset 布尔值 请参阅 Scaffold 的 resizeToAvoidBottomInset 属性。
initialSearchString 字符串 设置自动完成搜索的初始搜索字符串
searchForInitialValue 布尔值 启动时是否为初始值自动搜索
forceAndroidLocationManager 布尔值 在 Android 设备上,您可以将其设置为 true,以强制 geolocator 插件使用 'LocationManager' 来确定位置,而不是使用 'FusedLocationProviderClient'。在 iOS 上,此选项将被忽略。
myLocationButtonCooldown 整数 “myLocationButton”的冷却时间(以秒为单位)。默认为 10 秒。
forceSearchOnZoomChanged 布尔值 缩放级别更改时是否允许搜索。默认为 false。
automaticallyImplyAppBarLeading 布尔值 默认情况下,顶部有一个返回按钮。设置为 false 将移除返回按钮。
autocompleteOnTrailingWhitespace 布尔值 是否允许自动完成在搜索末尾的空格上运行。默认为 false。问题参考 #54。

有关自动完成搜索的更多信息,请参阅 Google 文档。

自定义选定地点可视化

默认情况下,当用户通过自动完成搜索或拖动地图选择一个地点时,我们会在屏幕底部显示信息(FloatingCard)。

但是,如果您不喜欢此 UI/UX,只需使用 ‘selectedPlaceWidgetBuilder’ 覆盖构建器即可。可以重用围绕屏幕浮动的 FlocatingCard 小部件,也可以构建一个全新的小部件。它与地图堆叠在一起,所以您可能需要使用 Positioned 小部件。

请注意,使用此自定义设置将不会调用 [onPlacePicked] 回调,因为它将覆盖浮动卡上的默认“选择此处”按钮!

...
PlacePicker(apiKey: APIKeys.apiKey,
            ...
            selectedPlaceWidgetBuilder: (_, selectedPlace, state, isSearchBarFocused) {
              return isSearchBarFocused
                  ? Container()
                  // Use FloatingCard or just create your own Widget.
                  : 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(onPressed: () { print("do something with [selectedPlace] data"); },),
                   );
            },
            ...
          ),
...
参数 类型 描述
context BuildContext Flutter 的 build context 值
selectedPlace PickResult 用户选择的地点结果数据
state SearchingState 搜索操作的状态。(空闲、搜索中)
isSearchBarFocused 布尔值 搜索栏当前是否聚焦,以便显示键盘

自定义图钉

默认情况下,图钉图标在移动时会提供非常简单的选择动画。但是,您也可以使用 ‘pinBuilder’ 创建自己的图钉小部件。

PlacePicker(apiKey: APIKeys.apiKey,
            ...
            pinBuilder: (context, state) {
                  if (state == PinState.Idle) {
                    return Icon(Icons.favorite_border);
                  } else {
                    return AnimatedIcon(.....);
                  }
                },
            ...                        
          ),
...
参数 类型 描述
context BuildContext Flutter 的 build context 值
state PinState 图钉的状态。(准备中;地图加载时、空闲、拖动中)

更改默认 FloatingCard 的颜色

虽然您可以构建自己的预测磁贴,但您仍然可以使用下面的 ThemeData 来更改默认磁贴的样式。

// 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,
  ),
);

功能请求和问题

请在 issue tracker 提交功能请求和错误。

您可能感兴趣的其他有用包

Firebase Auth Simplify Material design Speed Dial

从不再活跃的原始包派生

Google Maps Place Picker Buy Me A Coffee

GitHub

查看 Github