Google Maps Place Picker
一个 Flutter 插件,它使用 Google Maps 小部件提供“地点选取”。
项目依赖以下包。
使用 Flutter 官方 google_maps_flutter 进行地图显示,使用 Baseflow 的 geolocator 获取当前位置,使用 hadrienlejard 的 google_maps_webservice 进行地点和地理编码 API 调用,使用 kevmoo 的 tuple 进行构建。
预览
支持
如果该插件对您有帮助或节省了您的时间,请随时给我买杯咖啡!? 我得到的咖啡越多,将来就能做出越多有用的项目。
入门
-
在 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。详细说明可以在 此处 找到。
简而言之就是
- 将以下内容添加到您的“gradle.properties”文件中
android.useAndroidX=true android.enableJetifier=true
- 确保您的 `android/app/build.gradle` 文件中的 `compileSdkVersion` 设置为 28
android { compileSdkVersion 28 ... }
- 确保您将所有 `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


