Flutter谷歌地点搜索插件google_places_flutter_api的使用
Flutter谷歌地点搜索插件google_places_flutter_api的使用
简介
google_places_flutter_api
是一个用于Flutter应用的Google Places自动补全插件。它可以帮助用户在应用中快速查找和选择地点。需要注意的是,使用Google Places API需要在Google Cloud平台上启用计费功能。
安装
在项目的 pubspec.yaml
文件的 dependencies
部分添加以下内容:
dependencies:
google_places_flutter_api: <latest_version>
请确保将 <latest_version>
替换为最新的版本号。
使用方法
以下是一个完整的示例代码,展示了如何使用 google_places_flutter_api
插件来实现地点搜索功能。
import 'dart:async';
import 'dart:math';
import 'package:google_api_headers/google_api_headers.dart';
import 'package:flutter/material.dart';
import 'package:google_places_flutter_api/google_places_flutter_api.dart';
import 'package:flutter_google_maps_webservices/places.dart';
const kGoogleApiKey = "API_KEY"; // 替换为你的Google API密钥
void main() {
runApp(const RoutesWidget());
}
final customTheme = ThemeData(
brightness: Brightness.dark,
inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4.00)),
),
contentPadding: EdgeInsets.symmetric(
vertical: 12.50,
horizontal: 10.00,
),
),
);
class RoutesWidget extends StatelessWidget {
const RoutesWidget({Key? key}) : super(key: key);
[@override](/user/override)
Widget build(BuildContext context) => MaterialApp(
title: "My App",
darkTheme: customTheme,
themeMode: ThemeMode.dark,
routes: {
"/": (_) => const MyApp(),
"/search": (_) => CustomSearchScaffold(),
},
);
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
[@override](/user/override)
_MyAppState createState() => _MyAppState();
}
final homeScaffoldKey = GlobalKey<ScaffoldState>();
final searchScaffoldKey = GlobalKey<ScaffoldState>();
class _MyAppState extends State<MyApp> {
Mode? _mode = Mode.overlay;
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
key: homeScaffoldKey,
appBar: AppBar(
title: const Text("My App"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_buildDropdownMenu(),
ElevatedButton(
onPressed: _handlePressButton,
child: const Text("Search places"),
),
ElevatedButton(
child: const Text("Custom"),
onPressed: () {
Navigator.of(context).pushNamed("/search");
},
),
],
),
),
);
}
Widget _buildDropdownMenu() => DropdownButton(
value: _mode,
items: const <DropdownMenuItem<Mode>>[
DropdownMenuItem<Mode>(
child: Text("Overlay"),
value: Mode.overlay,
),
DropdownMenuItem<Mode>(
child: Text("Fullscreen"),
value: Mode.fullscreen,
),
],
onChanged: (dynamic m) {
setState(() {
_mode = m;
});
},
);
void onError(PlacesAutocompleteResponse response) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(response.errorMessage!)),
);
}
Future<void> _handlePressButton() async {
// 显示自动补全输入框并获取用户选择的预测结果
Prediction? p = await PlacesAutocomplete.show(
context: context,
apiKey: kGoogleApiKey,
onError: onError,
mode: _mode!,
language: "fr", // 设置语言为法语
decoration: InputDecoration(
hintText: 'Search',
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: const BorderSide(
color: Colors.white,
),
),
),
components: [Component(Component.country, "fr")], // 限制搜索范围为法国
);
if (p != null) {
displayPrediction(p, context);
}
}
}
Future<void> displayPrediction(Prediction? p, BuildContext context) async {
if (p != null) {
// 获取地点详情(纬度/经度)
GoogleMapsPlaces _places = GoogleMapsPlaces(
apiKey: kGoogleApiKey,
apiHeaders: await const GoogleApiHeaders().getHeaders(),
);
PlacesDetailsResponse detail =
await _places.getDetailsByPlaceId(p.placeId!);
final lat = detail.result.geometry!.location.lat;
final lng = detail.result.geometry!.location.lng;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("${p.description} - $lat/$lng")),
);
}
}
// 自定义搜索页面,继承自 PlacesAutocompleteWidget
class CustomSearchScaffold extends PlacesAutocompleteWidget {
CustomSearchScaffold({Key? key})
: super(
key: key,
apiKey: kGoogleApiKey,
sessionToken: Uuid().generateV4(),
language: "en", // 设置语言为英语
components: [Component(Component.country, "uk")], // 限制搜索范围为英国
);
[@override](/user/override)
_CustomSearchScaffoldState createState() => _CustomSearchScaffoldState();
}
class _CustomSearchScaffoldState extends PlacesAutocompleteState {
[@override](/user/override)
Widget build(BuildContext context) {
final appBar = AppBar(title: const AppBarPlacesAutoCompleteTextField());
final body = PlacesAutocompleteResult(
onTap: (p) {
displayPrediction(p, context);
},
logo: const Row(
children: [FlutterLogo()],
mainAxisAlignment: MainAxisAlignment.center,
),
);
return Scaffold(key: searchScaffoldKey, appBar: appBar, body: body);
}
[@override](/user/override)
void onResponseError(PlacesAutocompleteResponse response) {
super.onResponseError(response);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(response.errorMessage!)),
);
}
[@override](/user/override)
void onResponse(PlacesAutocompleteResponse? response) {
super.onResponse(response);
if (response != null && response.predictions.isNotEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Got answer")),
);
}
}
}
class Uuid {
final Random _random = Random();
String generateV4() {
// 生成UUID v4格式的字符串
final int special = 8 + _random.nextInt(4);
return '${_bitsDigits(16, 4)}${_bitsDigits(16, 4)}-'
'${_bitsDigits(16, 4)}-'
'4${_bitsDigits(12, 3)}-'
'${_printDigits(special, 1)}${_bitsDigits(12, 3)}-'
'${_bitsDigits(16, 4)}${_bitsDigits(16, 4)}${_bitsDigits(16, 4)}';
}
String _bitsDigits(int bitCount, int digitCount) =>
_printDigits(_generateBits(bitCount), digitCount);
int _generateBits(int bitCount) => _random.nextInt(1 << bitCount);
String _printDigits(int value, int count) =>
value.toRadixString(16).padLeft(count, '0');
}
更多关于Flutter谷歌地点搜索插件google_places_flutter_api的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter谷歌地点搜索插件google_places_flutter_api的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何使用 google_places_flutter_api
插件在 Flutter 中进行谷歌地点搜索的示例代码。这个插件允许你使用 Google Places API 来搜索地点、获取地点详细信息等。
首先,确保你已经在 pubspec.yaml
文件中添加了 google_places_flutter_api
依赖:
dependencies:
flutter:
sdk: flutter
google_places_flutter_api: ^x.y.z # 请替换为最新版本号
然后,运行 flutter pub get
来安装依赖。
接下来,你需要在 Android 和 iOS 项目中配置 Google Places API 的密钥。
Android 配置
- 在
android/app/src/main/AndroidManifest.xml
中添加以下权限:
<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" />
- 在
android/app/build.gradle
中添加 Google Places 服务的依赖:
dependencies {
implementation 'com.google.android.libraries.places:places:2.4.0' // 请根据需要替换为最新版本
}
- 在 Firebase 项目中启用 Places API 并获取 API 密钥,然后在
android/app/src/main/res/values/strings.xml
中添加你的 API 密钥(注意:出于安全考虑,最好不要在代码中硬编码 API 密钥,而是使用环境变量或 Firebase 配置):
<resources>
<string name="google_api_key">YOUR_API_KEY_HERE</string>
</resources>
iOS 配置
- 在你的 iOS 项目中,打开
Info.plist
并添加以下权限:
<key>NSLocationWhenInUseUsageDescription</key>
<string>需要访问您的位置以搜索地点</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>需要始终访问您的位置以搜索地点</string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
- 在 Firebase 项目中启用 Places API 并获取 API 密钥,然后在你的 iOS 项目中的某个地方(如
AppDelegate.swift
或Info.plist
的自定义配置中)存储你的 API 密钥。
Flutter 代码示例
以下是一个简单的 Flutter 示例,展示如何使用 google_places_flutter_api
进行地点搜索:
import 'package:flutter/material.dart';
import 'package:google_places_flutter_api/models/predictions.dart';
import 'package:google_places_flutter_api/models/place_details.dart';
import 'package:google_places_flutter_api/google_places_flutter_api.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Google Places Flutter API Example'),
),
body: PlaceSearchScreen(),
),
);
}
}
class PlaceSearchScreen extends StatefulWidget {
@override
_PlaceSearchScreenState createState() => _PlaceSearchScreenState();
}
class _PlaceSearchScreenState extends State<PlaceSearchScreen> {
final _placesController = TextEditingController();
List<Prediction> _predictions = [];
PlaceDetails? _placeDetails;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextField(
controller: _placesController,
decoration: InputDecoration(
prefixIcon: Icon(Icons.search),
labelText: 'Search for a place',
suffixIcon: IconButton(
icon: Icon(Icons.search),
onPressed: _searchPlaces,
),
),
),
SizedBox(height: 16),
Expanded(
child: _predictions.isEmpty
? Center(child: Text('No predictions found'))
: ListView.builder(
itemCount: _predictions.length,
itemBuilder: (context, index) {
Prediction prediction = _predictions[index];
return ListTile(
title: Text(prediction.description ?? ''),
subtitle: Text(prediction.placeId ?? ''),
onTap: () => _getPlaceDetails(prediction.placeId ?? ''),
);
}),
),
if (_placeDetails != null)
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Place Name: ${_placeDetails!.name}'),
Text('Place Address: ${_placeDetails!.formattedAddress}'),
Text('Place Rating: ${_placeDetails!.rating?.toString()}'),
],
),
),
),
),
],
),
);
}
Future<void> _searchPlaces() async {
if (_placesController.text.isEmpty) {
setState(() {
_predictions = [];
});
return;
}
try {
final predictionsResult = await GooglePlacesApiClient.placesAutocomplete(
input: _placesController.text,
apiKey: 'YOUR_API_KEY_HERE', // 替换为你的API密钥
sessionToken: 'SESSION_TOKEN', // 可选,用于跟踪会话
components: 'country:us', // 可选,用于限制搜索范围
type: 'geocode', // 可选,用于指定搜索类型
);
setState(() {
_predictions = predictionsResult.predictions ?? [];
});
} catch (e) {
print('Error searching places: $e');
}
}
Future<void> _getPlaceDetails(String placeId) async {
try {
final placeDetailsResult = await GooglePlacesApiClient.getPlaceDetails(
placeId: placeId,
apiKey: 'YOUR_API_KEY_HERE', // 替换为你的API密钥
fields: 'name,rating,formatted_address', // 可选,指定要返回的字段
);
setState(() {
_placeDetails = placeDetailsResult.result;
});
} catch (e) {
print('Error getting place details: $e');
}
}
}
请注意,在上面的代码中,你需要将 'YOUR_API_KEY_HERE'
替换为你的实际 Google Places API 密钥。同时,出于安全考虑,不建议在客户端代码中硬编码 API 密钥。你可以考虑使用环境变量或 Firebase 配置来管理 API 密钥。
此外,这个示例代码使用了 GooglePlacesApiClient
的静态方法来进行地点搜索和获取地点详细信息。确保你按照插件的文档正确初始化和配置客户端。
希望这个示例能帮到你!如果有任何问题,请随时提问。