Flutter地点选择插件google_maps_places_picker_refractored的使用
Flutter地点选择插件google_maps_places_picker_refractored的使用
Google Maps Places Picker Refractored
这是一个对fysoul17/google_maps_place_picker插件的分叉版本,增加了自定义样式和功能。所有功劳归于原始开发者。
该插件通过Flutter的google_maps_flutter
小部件提供了一个“地点选择”功能。
项目依赖以下包:
- 使用Flutter官方的
google_maps_flutter
绘制地图。 - 使用Baseflow的
geolocator
获取当前位置。 - 使用hadrienlejard的
google_maps_webservice
调用Place和Geocoding API。 - 使用kevmoo的
tuple
构建器。
预览
支持
如果本插件对你有用或节省了你的时间,请考虑买杯咖啡支持我!
更多咖啡意味着未来能制作更有用的项目。
入门指南
获取API密钥
访问https://cloud.google.com/maps-platform/获取API密钥。
启用Google Maps SDK
- 前往Google开发者控制台。
- 选择你要启用Google Maps的项目。
- 在导航菜单中选择“Google Maps”。
- 点击“APIs”,然后在“附加APIs”部分启用以下选项:
- 对于Android,启用“Maps SDK for Android”。
- 对于iOS,启用“Maps SDK for iOS”。
- 确保启用的API出现在“已启用APIs”部分。
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项目也升级到支持AndroidX。详细说明可以参考这里。
以下是快速解决步骤:
- 在
gradle.properties
文件中添加以下内容:android.useAndroidX=true android.enableJetifier=true
- 将
android/app/build.gradle
文件中的compileSdkVersion
设置为28:android { compileSdkVersion 28 ... }
- 替换所有
android.
依赖项为对应的AndroidX版本(完整列表可参考这里)。
iOS配置
在应用委托文件ios/Runner/AppDelegate.m
中添加API密钥:
#import "AppDelegate.h"
#import "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代码中,添加API密钥到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)
}
}
在iOS上,为了访问设备位置,你需要在Info.plist
文件中添加以下键值对:
<key>NSLocationWhenInUseUsageDescription</key>
<string>此应用需要在打开时访问您的位置。</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>此应用需要在后台访问您的位置。</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>此应用需要在打开和后台时访问您的位置。</string>
此外,你需要在XCode项目中启用Background Modes
能力,并选择Location Updates
。
为了嵌入视图预览,向应用的Info.plist
文件中添加一个布尔属性,键为io.flutter.embedded_views_preview
,值为YES
:
<key>io.flutter.embedded_views_preview</key>
<true/>
使用方法
基本用法
你可以通过Navigator.push
跳转到新页面,也可以将PlacePicker
作为任何小部件的子组件。
当用户在地图上选择一个地点时,它会通过onPlacePicked
回调返回PickResult
类型的结果。你也可以通过selectedPlaceWidgetBuilder
构建自己的方式来获取结果。
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PlacePicker(
apiKey: APIKeys.apiKey, // 替换为你的API密钥
onPlacePicked: (result) {
print(result.address); // 打印选中的地址
Navigator.of(context).pop();
},
initialPosition: HomePage.kInitialPosition, // 初始地图中心位置
useCurrentLocation: true, // 是否使用设备当前位置
),
),
);
PickResult 类型
PickResult
包含以下字段:
参数 | 类型 | 描述 |
---|---|---|
placeId |
String |
地点的唯一标识符,用于获取地点详情。 |
geometry |
Geometry |
包含地点的几何信息,如位置和视口。 |
formattedAddress |
String |
地点的人类可读地址。 |
types |
List<String> |
地点类型的数组。 |
addressComponents |
List<AddressComponent> |
地址的组成部分数组。 |
可选字段(仅在启用自动补全搜索或usePlaceDetailSearch
为true
时返回):
参数 | 类型 | 描述 |
---|---|---|
adrAddress |
String |
地点的adr微格式表示。 |
formattedPhoneNumber |
String |
地点的本地格式电话号码。 |
id |
String |
地点的唯一ID(未在Google文档中记录)。 |
reference |
String |
地点的引用(未在Google文档中记录)。 |
icon |
String |
地点图标URL。 |
name |
String |
地点的名称。 |
openingHours |
OpeningHoursDetail |
地点的营业时间信息。 |
photos |
List<Photo> |
地点的照片数组。 |
internationalPhoneNumber |
String |
地点的国际格式电话号码。 |
priceLevel |
PriceLevel |
地点的价格等级(0-4)。 |
rating |
num |
地点的评分(1.0-5.0)。 |
url |
String |
地点的官方Google页面URL。 |
vicinity |
String |
简化版地址,包括街道名、编号和城市,但不包括省份、邮政编码或国家。 |
utcOffset |
num |
地点当前时区与UTC的偏移量(分钟)。 |
website |
String |
地点的权威网站。 |
reviews |
List<Review> |
地点的最多五条评论。 |
更多关于PickResult
的信息可以参考Google文档。
PlacePicker 参数
PlacePicker
支持以下参数:
参数 | 类型 | 描述 |
---|---|---|
apiKey |
String |
必填,Google Maps API密钥。 |
onPlacePicked |
Callback(PickResult) |
当用户选择地点并确认时触发。 |
initialPosition |
LatLng |
必填,初始地图中心位置。如果useCurrentLocation 为true ,则尝试获取设备当前位置。 |
useCurrentLocation |
bool |
是否使用设备当前位置作为初始中心位置。 |
desiredLocationAccuracy |
LocationAccuracy |
获取当前位置的精度,默认为高精度。 |
hintText |
String |
搜索栏提示文本。 |
searchingText |
String |
搜索进行时显示的文本,默认为“Searching…”。 |
proxyBaseUrl |
String |
用于Google Maps API调用的代理基础URL。 |
httpClient |
Client |
用于Google Maps API调用的HTTP客户端。 |
autoCompleteDebounceInMilliseconds |
int |
自动补全输入的去抖动时间,默认为500毫秒。 |
cameraMoveDebounceInMilliseconds |
int |
地图拖动时搜索的去抖动时间,默认为750毫秒。 |
intialMapType |
MapType |
地图类型,默认为普通地图。 |
enableMapTypeButton |
bool |
是否显示地图类型切换按钮。 |
enableMyLocationButton |
bool |
是否显示我的位置按钮。 |
usePinPointingSearch |
bool |
默认为true ,允许用户拖动地图以获取指针指向位置的信息。 |
usePlaceDetailSearch |
bool |
默认为false ,设置为true 时,拖动地图搜索会获取更详细的地点信息,但会额外消耗一个Place Details API请求。 |
onAutoCompleteFailed |
Callback(String) |
自动补全搜索失败时触发。 |
onGeocodingSearchFailed |
Callback(String) |
拖动地图搜索失败时触发。 |
onMapCreated |
MapCreatedCallback |
地图创建完成后返回控制器。 |
selectedPlaceWidgetBuilder |
WidgetBuilder |
自定义选中地点的UI。 |
pinBuilder |
WidgetBuilder |
自定义地图上的指针。 |
autocompleteOffset |
num |
自动补全搜索的偏移量。 |
autocompleteRadius |
num |
自动补全搜索的半径范围。 |
autocompleteLanguage |
String |
自动补全搜索的语言代码。 |
autocompleteComponents |
List<Components> |
限制搜索结果的区域。 |
autocompleteTypes |
List<String> |
限制搜索结果的地点类型。 |
strictbounds |
bool |
仅返回严格位于指定区域内的地点。 |
region |
String |
限制搜索结果的国家代码。 |
selectInitialPosition |
bool |
是否在初始加载时显示选中的地点。 |
resizeToAvoidBottomInset |
bool |
参考Scaffold的resizeToAvoidBottomInset 属性。 |
initialSearchString |
String |
设置初始搜索字符串。 |
searchForInitialValue |
bool |
是否在启动时自动搜索初始值。 |
forceAndroidLocationManager |
bool |
强制Android设备使用LocationManager 获取位置。 |
myLocationButtonCooldown |
int |
“我的位置”按钮的冷却时间,默认为10秒。 |
forceSearchOnZoomChanged |
bool |
是否允许在缩放变化时进行搜索,默认为false 。 |
automaticallyImplyAppBarLeading |
bool |
是否默认显示返回按钮,默认为true 。 |
autocompleteOnTrailingWhitespace |
bool |
是否允许在搜索末尾空格时进行自动补全,默认为false 。 |
All Of the input decoration props |
InputDecoration |
样式搜索文本框。 |
borderRadius |
BorderRadiusGeometry? |
输入框容器的圆角。 |
isInScaffoldBodyAndHasAppBar |
bool (default=true) |
是否将地点选择器包裹在带有AppBar的Scaffold中。 |
height |
double? |
输入框容器的高度。 |
更多关于自动补全搜索的信息可以参考Google文档。
自定义选中地点的可视化
默认情况下,当用户通过自动补全搜索或拖动地图选择地点时,信息会在屏幕底部(FloatingCard)显示。
如果你不喜欢这种UI/UX,可以通过selectedPlaceWidgetBuilder
覆盖默认的构建器。可以重用FloatingCard
或完全根据需求构建新的小部件。它会叠加在地图上,因此建议使用Positioned
小部件。
注意:使用此自定义方法不会触发onPlacePicked
回调,因为它会覆盖默认的“选择这里”按钮。
PlacePicker(
apiKey: APIKeys.apiKey,
...
selectedPlaceWidgetBuilder: (_, selectedPlace, state, isSearchBarFocused) {
return isSearchBarFocused
? Container()
: FloatingCard(
bottomPosition: 0.0,
leftPosition: 0.0,
rightPosition: 0.0,
width: 500,
borderRadius: BorderRadius.circular(12.0),
child: state == SearchingState.Searching
? Center(child: CircularProgressIndicator())
: ElevatedButton(
onPressed: () {
print("do something with [selectedPlace] data");
},
child: Text("Pick Here"),
),
);
},
...
),
参数说明:
参数 | 类型 | 描述 |
---|---|---|
context |
BuildContext |
Flutter的构建上下文值。 |
selectedPlace |
PickResult |
用户选择地点的结果数据。 |
state |
SearchingState |
搜索操作的状态(Idle, Searching)。 |
isSearchBarFocused |
bool |
是否搜索栏处于聚焦状态,键盘是否显示。 |
自定义地图指针
默认情况下,地图指针具有简单的移动动画。你可以通过pinBuilder
创建自定义指针。
PlacePicker(
apiKey: APIKeys.apiKey,
...
pinBuilder: (context, state) {
if (state == PinState.Idle) {
return Icon(Icons.favorite_border);
} else {
return AnimatedIcon(...);
}
},
...
),
参数说明:
参数 | 类型 | 描述 |
---|---|---|
context |
BuildContext |
Flutter的构建上下文值。 |
state |
PinState |
指针的状态(Preparing, Idle, Dragging)。 |
更改默认FloatingCard的颜色
即使你构建了自己的预测小部件,仍然可以通过themeData
更改默认小部件的样式。
// 浅色主题
final ThemeData lightTheme = ThemeData.light().copyWith(
cardColor: Colors.white, // FloatingCard背景颜色
buttonTheme: ButtonThemeData(
buttonColor: Colors.black, // 选择按钮颜色
textTheme: ButtonTextTheme.primary,
),
);
// 深色主题
final ThemeData darkTheme = ThemeData.dark().copyWith(
cardColor: Colors.grey, // FloatingCard背景颜色
buttonTheme: ButtonThemeData(
buttonColor: Colors.yellow, // 选择按钮颜色
textTheme: ButtonTextTheme.primary,
),
);
更多关于Flutter地点选择插件google_maps_places_picker_refractored的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter地点选择插件google_maps_places_picker_refractored的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
google_maps_places_picker_refractored
是一个用于在 Flutter 应用中选择地点的插件,它基于 Google Maps Places API。该插件允许用户通过地图选择地点,并返回地点的详细信息。
安装插件
首先,你需要在 pubspec.yaml
文件中添加依赖:
dependencies:
flutter:
sdk: flutter
google_maps_places_picker_refractored: ^1.0.0
然后运行 flutter pub get
来安装依赖。
获取 Google Maps API 密钥
在使用该插件之前,你需要获取一个 Google Maps API 密钥。你可以在 Google Cloud Console 中创建一个项目并启用 Google Maps JavaScript API 和 Places API。
配置 Android 和 iOS
Android:
在 android/app/src/main/AndroidManifest.xml
文件中添加以下代码:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<application
android:name=".MyApplication"
android:label="MyApp"
android:icon="@mipmap/ic_launcher">
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="YOUR_GOOGLE_MAPS_API_KEY"/>
</application>
</manifest>
iOS:
在 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_GOOGLE_MAPS_API_KEY")
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
使用插件
在你的 Flutter 应用中,你可以使用 GoogleMapsPlacesPicker
来打开地点选择器,并获取用户选择的地点信息。
import 'package:flutter/material.dart';
import 'package:google_maps_places_picker_refractored/google_maps_places_picker.dart';
import 'package:google_maps_places_picker_refractored/providers/place_provider.dart';
import 'package:google_maps_places_picker_refractored/models/pick_result.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Google Maps Place Picker',
home: PlacePickerExample(),
);
}
}
class PlacePickerExample extends StatefulWidget {
[@override](/user/override)
_PlacePickerExampleState createState() => _PlacePickerExampleState();
}
class _PlacePickerExampleState extends State<PlacePickerExample> {
PickResult? selectedPlace;
void _openPlacePicker() async {
PickResult? result = await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => PlacePicker(
apiKey: "YOUR_GOOGLE_MAPS_API_KEY",
onPlacePicked: (PickResult result) {
Navigator.of(context).pop();
setState(() {
selectedPlace = result;
});
},
initialPosition: LatLng(37.4219999, -122.0862462), // 初始位置
useCurrentLocation: true, // 是否使用当前定位
),
),
);
if (result != null) {
setState(() {
selectedPlace = result;
});
}
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Google Maps Place Picker'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
if (selectedPlace != null)
Text('Selected Place: ${selectedPlace!.formattedAddress}'),
ElevatedButton(
onPressed: _openPlacePicker,
child: Text('Pick a Place'),
),
],
),
),
);
}
}