Flutter地点搜索与选择插件google_places_sdk的使用
Flutter 地点搜索与选择插件 google_places_sdk
的使用
google_places_sdk
是一个支持 Android 和 iOS 的 Flutter 插件,用于集成 Google Places SDK。本文将详细介绍如何使用该插件进行地点搜索和选择。
平台支持
Platform | Version |
---|---|
Android | SDK 16+ |
iOS | iOS 11+ |
Web | Not supported |
Linux | Not supported |
MacOS | Not supported |
Windows | Not supported |
功能支持
Feature | Android | iOS |
---|---|---|
Soft Localization | ✅ | ❌ |
Device Localizations | ✅ | ✅ |
Place Autocomplete | ✅ | ✅ |
Place Details | ✅ | ✅ |
Current Place | ❌ | ❌ |
Place Photo | ✅ | ✅ |
Request Cancellation | ✅ | ❌ |
使用步骤
初始化插件
首先,需要在 pubspec.yaml
文件中添加 google_places
依赖,并初始化插件:
dependencies:
google_places: ^latest_version
然后,在 Dart 代码中初始化插件:
await GooglePlaces().initialize(
"Your maps key here",
locale: const Locale('ar'),
);
更改语言环境
你可以更改语言环境(仅支持 Android):
await GooglePlaces().updateLocale(const Locale('en'));
获取自动补全结果
初始化插件后,可以通过查询获取自动补全搜索结果:
final List<AutocompletePrediction> results = await GooglePlaces().getAutoCompletePredictions('Great Pyramid of Giza');
参数说明:
query
: 查询字符串(必需)countryCodes
: 国家代码列表(可选)locationBias
: 矩形边界(可选)locationRestriction
: 矩形限制(可选)placeTypes
: 地点类型列表(可选)cancellationToken
: 取消令牌(可选)
获取地点详情
通过传递地点 ID 获取地点详情:
final PlaceDetails placeDetails = await GooglePlaces.fetchPlaceDetails('Your Place Id');
参数说明:
placeId
: 地点 ID(必需)placeFields
: 地点字段列表(可选)cancellationToken
: 取消令牌(可选)
获取地点照片
获取地点详情后,可以进一步获取地点的照片:
final Uint8List? photo = await GooglePlaces().fetchPlacePhoto(widget.metadata);
取消请求
插件支持取消对 Google API 的请求(仅支持 Android):
final token = CancellationToken();
final details = await GooglePlaces.fetchPlaceDetails('Your Place Id', cancellationToken: token);
await token.cancel();
注意:发出取消令牌并不能保证特定请求会被取消,即使没有返回响应,您仍可能被收费。
示例 Demo
以下是一个完整的示例应用,展示了如何使用 google_places_sdk
进行地点搜索和选择:
import 'dart:async';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:google_places_sdk/google_places_sdk.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
initPlatformState();
}
Future<void> initPlatformState() async {
await GooglePlaces().initialize(
const String.fromEnvironment("MAPS_KEY"),
locale: const Locale('ar'),
);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Plugin example app')),
body: const _HomePageContents(),
),
);
}
}
class _HomePageContents extends StatelessWidget {
const _HomePageContents();
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () => Navigator.push(context,
MaterialPageRoute(builder: (_) => const AutocompletePage())),
child: const Text('Autocomplete'))
],
),
);
}
}
class AutocompletePage extends StatefulWidget {
const AutocompletePage({super.key});
@override
State<AutocompletePage> createState() => _AutocompletePageState();
}
class _AutocompletePageState extends State<AutocompletePage> {
final _predictions = <AutocompletePrediction>[];
final _controller = TextEditingController();
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Builder(
builder: (context) {
return Scaffold(
appBar: AppBar(title: const Text('Plugin example app')),
body: Center(
child: ListView(
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 10),
child: TextField(
controller: _controller,
decoration: const InputDecoration(border: OutlineInputBorder()),
onSubmitted: (val) async {
GooglePlaces().getAutoCompletePredictions(val, countryCodes: ['SA']).then(
(value) => setState(() {
_predictions.clear();
_predictions.addAll(value);
}),
);
},
),
),
ElevatedButton(
onPressed: () async {
GooglePlaces().getAutoCompletePredictions(
_controller.text,
countryCodes: ['SA'],
placeTypes: [PlaceType.restaurant],
).then((value) => setState(() {
_predictions.clear();
_predictions.addAll(value);
}));
},
child: const Text("Submit")),
..._predictions.map(
(e) => AutoCompleteTile(prediction: e),
)
],
),
),
);
},
),
);
}
}
class AutoCompleteTile extends StatelessWidget {
final AutocompletePrediction prediction;
const AutoCompleteTile({super.key, required this.prediction});
@override
Widget build(BuildContext context) {
return Table(
children: [
TableRow(children: [
const Text('Place ID'),
TextButton(
onPressed: () {
if (prediction.placeId == null) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Place Id not found')));
}
navigateToPage(context, placeId: prediction.placeId!);
},
child: Text(prediction.placeId ?? ''))
]),
TableRow(children: [
const Text('Full name'),
Text(prediction.fullName ?? '')
]),
TableRow(children: [
const Text('Primary text'),
Text(prediction.primaryText ?? '')
]),
TableRow(children: [
const Text('Secondary text'),
Text(prediction.secondaryText ?? '')
]),
TableRow(children: [const Text('PlaceTypes'), Container()]),
...prediction.placeTypes
.map((t) => TableRow(children: [Container(), Text(t.value)]))
.toList()
],
);
}
void navigateToPage(BuildContext context, {required String placeId}) {
Navigator.push(context,
MaterialPageRoute(builder: (_) => PlaceDetailsPage(placeId: placeId)));
}
}
class PlaceDetailsPage extends StatefulWidget {
final String placeId;
const PlaceDetailsPage({super.key, required this.placeId});
@override
State<StatefulWidget> createState() => _PlaceDetailsPageState();
}
class _PlaceDetailsPageState extends State<PlaceDetailsPage> {
PlaceDetails? details;
@override
void initState() {
super.initState();
initPlatformState();
}
Future<void> initPlatformState() async {
GooglePlaces()
.fetchPlaceDetails(widget.placeId)
.then((value) => setState(() => details = value));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(details?.name ?? '')),
body: SingleChildScrollView(
child: Table(
children: [
TableRow(children: [
const Text('Place ID'),
Text(details?.placeId ?? '')
]),
TableRow(children: [const Text('Name'), Text(details?.name ?? '')]),
TableRow(children: [
const Text('Coords'),
Text('(${details?.latLng?.lat}, ${details?.latLng?.lng})')
]),
TableRow(children: [
const Text('Address'),
Text(details?.address ?? '')
]),
TableRow(children: [
const Text('Business Status'),
Text(details?.businessStatus?.value ?? '')
]),
TableRow(children: [
const Text('Curbside Pickup'),
Text(details?.curbsidePickup.toString() ?? '')
]),
TableRow(children: [
const Text('Delivery'),
Text(details?.delivery.toString() ?? '')
]),
TableRow(children: [
const Text('Dine in'),
Text(details?.dineIn.toString() ?? '')
]),
TableRow(children: [
const Text('Icon Background Color'),
Text(details?.iconBackgroundColor.toString() ?? '')
]),
TableRow(children: [
const Text('Icon URL'),
Text(details?.iconURL ?? '')
]),
TableRow(children: [
const Text('Opening Hours'),
Text(details?.openingHours.toString() ?? '')
]),
TableRow(children: [
const Text('Phone Number'),
Text(details?.phoneNumber ?? '')
]),
TableRow(children: [const Text('Photos Metadata'), Container()]),
...details?.photoMetadatas
?.map((m) => TableRow(children: [
Container(),
PhotoMetadataTile(metadata: m)
]))
.toList() ??
[],
TableRow(children: [
const Text('Plus Code'),
Text(details?.plusCode.toString() ?? '')
]),
TableRow(children: [
const Text('Price Level'),
Text(details?.priceLevel?.id.toString() ?? '')
]),
TableRow(children: [
const Text('Rating'),
Text(details?.rating.toString() ?? '')
]),
TableRow(children: [
const Text('Place Types'),
Text(details?.placeTypes.toString() ?? '')
]),
TableRow(children: [
const Text('User Rating Total'),
Text(details?.userRatingTotal.toString() ?? '')
]),
TableRow(children: [
const Text('UTC Offset Minutes'),
Text(details?.utcOffsetMinutes.toString() ?? '')
]),
TableRow(children: [
const Text('Viewport'),
Text(details?.viewport.toString() ?? '')
]),
TableRow(children: [
const Text('Website URI'),
Text(details?.websiteURI?.toString() ?? '')
]),
TableRow(children: [
const Text('Is Open'),
Text(details?.isOpen.toString() ?? '')
]),
],
),
),
);
}
}
class PhotoMetadataTile extends StatelessWidget {
final PhotoMetadata metadata;
const PhotoMetadataTile({super.key, required this.metadata});
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('$metadata'),
TextButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => PlacePhotoPage(metadata: metadata))),
child: const Text('Show photo'),
)
],
);
}
}
class PlacePhotoPage extends StatefulWidget {
final PhotoMetadata metadata;
const PlacePhotoPage({super.key, required this.metadata});
@override
State<StatefulWidget> createState() => _PlacePhotoPageState();
}
class _PlacePhotoPageState extends State<PlacePhotoPage> {
Uint8List? photo;
@override
void initState() {
super.initState();
GooglePlaces()
.fetchPlacePhoto(widget.metadata)
.then((value) => setState(() => photo = value));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Photo')),
body: Center(
child: photo == null ? const Text('No image yet') : Image.memory(photo!),
),
);
}
}
这个示例应用展示了如何使用 google_places_sdk
插件进行地点搜索、获取地点详情以及显示地点照片。希望对你有所帮助!
更多关于Flutter地点搜索与选择插件google_places_sdk的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter地点搜索与选择插件google_places_sdk的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter项目中使用google_places_sdk
插件来实现地点搜索与选择的代码示例。这个插件允许你集成Google Places API,从而提供地点搜索和自动完成功能。
首先,确保你已经在pubspec.yaml
文件中添加了google_places_sdk
依赖:
dependencies:
flutter:
sdk: flutter
google_places_sdk: ^x.y.z # 请替换为最新版本号
然后,运行flutter pub get
来安装依赖。
接下来,你需要配置Google Places API。确保你已经在Google Cloud Platform上启用了Places API,并创建了API密钥。然后,在你的android/app/src/main/AndroidManifest.xml
文件中添加以下权限和API密钥配置:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.yourapp">
<!-- 添加必要的权限 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<application
... >
<!-- 添加API密钥的meta-data -->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="YOUR_API_KEY_HERE" />
...
</application>
</manifest>
确保将YOUR_API_KEY_HERE
替换为你的实际API密钥。
现在,你可以在你的Flutter代码中实现地点搜索和选择功能。以下是一个简单的示例:
import 'package:flutter/material.dart';
import 'package:google_places_sdk/google_places_sdk.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: PlacePickerScreen(),
);
}
}
class PlacePickerScreen extends StatefulWidget {
@override
_PlacePickerScreenState createState() => _PlacePickerScreenState();
}
class _PlacePickerScreenState extends State<PlacePickerScreen> {
late PlacesClient _placesClient;
late AutocompleteSessionToken _sessionToken;
@override
void initState() {
super.initState();
_placesClient = PlacesClient.create();
_sessionToken = AutocompleteSessionToken.current();
}
void _onPlaceSelected(Place place) {
// 处理选中的地点
print('Selected place: ${place.name}, ${place.placeId}');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('地点搜索与选择'),
),
body: Center(
child: ElevatedButton(
onPressed: () async {
try {
Prediction? prediction = await _placesClient.autocompleteQuery(
AutocompleteRequest(
sessionToken: _sessionToken,
input: '餐厅',
type: PlaceType.restaurant,
),
);
if (prediction != null) {
// 获取地点的详细信息
Place? place = await _placesClient.getPlaceDetails(
PlaceDetailsRequest(placeId: prediction.placeId),
);
if (place != null) {
_onPlaceSelected(place);
}
}
} catch (e) {
print('Error: $e');
}
},
child: Text('搜索餐厅'),
),
),
);
}
}
在这个示例中,我们创建了一个简单的Flutter应用,其中包含一个按钮,用于触发地点搜索。当用户点击按钮时,应用将使用google_places_sdk
插件来搜索与“餐厅”相关的地点,并在控制台中打印选中地点的名称和ID。
请注意,这个示例仅展示了基本的搜索功能。在实际应用中,你可能需要处理更多的细节,例如用户权限请求、错误处理、UI设计等。此外,请确保你的API密钥受到适当的保护,避免在客户端代码中硬编码API密钥,最好使用更安全的方法来管理API密钥。