Flutter谷歌地点服务插件google_place_plus的使用
Flutter谷歌地点服务插件google_place_plus
的使用
简介
google_place_plus
是一个支持iOS、Android和Web平台的Flutter插件,提供了Google Places API的功能。该插件是从 bazrafkan/google_place 分支出来的,并对其进行了改进。
功能预览
通过HTTP请求,Google Places API可以返回关于地点的信息。这些地点包括商家、地理位置或著名的兴趣点。以下是一些可用的API请求:
- Place Search:根据用户的位置或搜索字符串返回地点列表。
- Place Details:返回特定地点的详细信息,包括用户评论。
- Place Photos:提供访问存储在Google Place数据库中的数百万张与地点相关的照片。
- Place Autocomplete:当用户输入时自动填写地点名称和/或地址。
- Query Autocomplete:为基于文本的地理搜索提供查询预测服务,在用户输入时返回建议查询。
使用方法
要在项目中使用此插件,请将 google_place_plus
添加为依赖项到您的 pubspec.yaml
文件中。
获取API密钥
首先,您需要从 Google Cloud Console 获取API密钥:
- 登录Google开发者控制台。
- 选择您要启用Google Place的项目。
示例代码
下面是一个完整的示例demo,展示了如何在Flutter应用中使用 google_place_plus
插件进行地点自动完成搜索并显示地点详情。
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:google_place_plus/google_place_plus.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await dotenv.load(fileName: ".env");
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
[@override](/user/override)
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
GooglePlace? googlePlace;
List<AutocompletePrediction> predictions = [];
[@override](/user/override)
void initState() {
String? apiKey = dotenv.env['API_KEY'];
if (apiKey != null) googlePlace = GooglePlace(apiKey);
super.initState();
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
margin: EdgeInsets.only(right: 20, left: 20, top: 20),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextField(
decoration: InputDecoration(
labelText: "Search",
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue, width: 2.0),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black54, width: 2.0),
),
),
onChanged: (value) {
if (value.isNotEmpty) {
autoCompleteSearch(value);
} else {
if (predictions.length > 0 && mounted) {
setState(() {
predictions = [];
});
}
}
},
),
SizedBox(height: 10),
Expanded(
child: ListView.builder(
itemCount: predictions.length,
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(
child: Icon(Icons.pin_drop, color: Colors.white),
),
title: Text(predictions[index].description ?? ''),
onTap: () {
debugPrint(predictions[index].placeId);
if (googlePlace == null) return;
if (predictions[index].placeId == null) return;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailsPage(
placeId: predictions[index].placeId!,
googlePlace: googlePlace!,
),
),
);
},
);
},
),
),
Container(
margin: EdgeInsets.only(top: 10, bottom: 10),
child: Image.asset("assets/powered_by_google.png"),
),
],
),
),
),
);
}
void autoCompleteSearch(String value) async {
var result = await googlePlace?.autocomplete.get(value);
if (result != null && result.predictions != null && mounted) {
setState(() {
predictions = result.predictions!;
});
}
}
}
class DetailsPage extends StatefulWidget {
final String placeId;
final GooglePlace googlePlace;
const DetailsPage({Key? key, required this.placeId, required this.googlePlace})
: super(key: key);
[@override](/user/override)
_DetailsPageState createState() => _DetailsPageState(this.placeId, this.googlePlace);
}
class _DetailsPageState extends State<DetailsPage> {
final String placeId;
final GooglePlace googlePlace;
DetailsResult? detailsResult;
List<Uint8List> images = [];
_DetailsPageState(this.placeId, this.googlePlace);
[@override](/user/override)
void initState() {
getDetails(this.placeId);
super.initState();
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Details"), backgroundColor: Colors.blueAccent),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.blueAccent,
onPressed: () {
getDetails(this.placeId);
},
child: Icon(Icons.refresh),
),
body: SafeArea(
child: Container(
margin: EdgeInsets.only(right: 20, left: 20, top: 20),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
height: 200,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: images.length,
itemBuilder: (context, index) {
return Container(
width: 250,
child: Card(
elevation: 4,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)),
child: ClipRRect(
borderRadius: BorderRadius.circular(10.0),
child: Image.memory(images[index], fit: BoxFit.fill),
),
),
);
},
),
),
SizedBox(height: 10),
Expanded(
child: Card(
elevation: 4,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)),
child: ListView(
children: <Widget>[
Container(
margin: EdgeInsets.only(left: 15, top: 10),
child: Text("Details", style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
),
detailsResult?.types != null
? Container(
margin: EdgeInsets.only(left: 15, top: 10),
height: 50,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: detailsResult!.types!.length,
itemBuilder: (context, index) {
return Container(
margin: EdgeInsets.only(right: 10),
child: Chip(
label: Text(detailsResult!.types![index], style: TextStyle(color: Colors.white)),
backgroundColor: Colors.blueAccent,
),
);
},
),
)
: Container(),
Container(
margin: EdgeInsets.only(left: 15, top: 10),
child: ListTile(
leading: CircleAvatar(child: Icon(Icons.location_on)),
title: Text('Address: ${detailsResult?.formattedAddress ?? "null"}'),
),
),
Container(
margin: EdgeInsets.only(left: 15, top: 10),
child: ListTile(
leading: CircleAvatar(child: Icon(Icons.location_searching)),
title: Text('Geometry: ${detailsResult?.geometry?.location?.lat}, ${detailsResult?.geometry?.location?.lng}'),
),
),
Container(
margin: EdgeInsets.only(left: 15, top: 10),
child: ListTile(
leading: CircleAvatar(child: Icon(Icons.timelapse)),
title: Text('UTC offset: ${detailsResult?.utcOffset ?? "null"} min'),
),
),
Container(
margin: EdgeInsets.only(left: 15, top: 10),
child: ListTile(
leading: CircleAvatar(child: Icon(Icons.rate_review)),
title: Text('Rating: ${detailsResult?.rating ?? "null"}'),
),
),
Container(
margin: EdgeInsets.only(left: 15, top: 10),
child: ListTile(
leading: CircleAvatar(child: Icon(Icons.attach_money)),
title: Text('Price level: ${detailsResult?.priceLevel ?? "null"}'),
),
),
],
),
),
),
Container(margin: EdgeInsets.only(top: 20, bottom: 10), child: Image.asset("assets/powered_by_google.png")),
],
),
),
),
);
}
void getDetails(String placeId) async {
var result = await this.googlePlace.details.get(placeId);
if (result != null && result.result != null && mounted) {
setState(() {
detailsResult = result.result;
images = [];
});
if (result.result?.photos != null) {
for (var photo in result.result!.photos!) {
getPhoto(photo.photoReference!);
}
}
}
}
void getPhoto(String photoReference) async {
var result = await this.googlePlace.photos.get(photoReference: photoReference, maxWidth: 400);
if (result != null && mounted) {
setState(() {
images.add(result);
});
}
}
}
更多关于Flutter谷歌地点服务插件google_place_plus的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter谷歌地点服务插件google_place_plus的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter项目中使用google_place_plus
插件来获取地点信息的代码示例。这个插件是google_maps_place_picker
的一个替代或增强版,用于在Flutter应用中集成谷歌地点服务。
首先,确保你已经在pubspec.yaml
文件中添加了google_place_plus
依赖:
dependencies:
flutter:
sdk: flutter
google_place_plus: ^latest_version # 请替换为最新版本号
然后运行flutter pub get
来安装依赖。
接下来,你需要在Android和iOS项目中配置API密钥和必要的权限。这通常涉及到在android/app/src/main/AndroidManifest.xml
中添加位置权限,以及在iOS的Info.plist
中添加相应的键。
Android配置
在AndroidManifest.xml
中添加以下权限:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
确保你的API密钥已经在android/app/build.gradle
文件中的manifestPlaceholders
里设置:
android {
...
defaultConfig {
...
manifestPlaceholders = [
'google_maps_android_api_key':'YOUR_ANDROID_API_KEY'
]
}
}
iOS配置
在Info.plist
中添加以下键:
<key>NSLocationWhenInUseUsageDescription</key>
<string>需要您的位置信息来搜索地点</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>需要您的位置信息来搜索地点</string>
<key>GOOGLE_API_KEY</key>
<string>YOUR_IOS_API_KEY</string>
注意:虽然GOOGLE_API_KEY
在iOS的Info.plist
中不是必需的(因为通常我们在iOS项目中通过其他方式管理API密钥,比如使用GoogleService-Info.plist),但确保你的API密钥在项目中正确配置是很重要的。
Flutter代码示例
下面是一个简单的Flutter应用示例,展示了如何使用google_place_plus
插件来搜索并显示地点信息:
import 'package:flutter/material.dart';
import 'package:google_place_plus/google_place_plus.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Google Place Plus Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: PlacePickerDemo(),
);
}
}
class PlacePickerDemo extends StatefulWidget {
@override
_PlacePickerDemoState createState() => _PlacePickerDemoState();
}
class _PlacePickerDemoState extends State<PlacePickerDemo> {
PlaceResult? selectedPlace;
Future<void> _pickPlace() async {
final PlacePickerResult result = await PlacePicker.show(
context: context,
apiKey: 'YOUR_API_KEY', // 在这里替换为你的API密钥
mode: Mode.overlay,
);
if (result != null && result.place != null) {
setState(() {
selectedPlace = result.place!;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Google Place Plus Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: _pickPlace,
child: Text('Pick a Place'),
),
if (selectedPlace != null)
Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Name: ${selectedPlace!.name}'),
Text('Address: ${selectedPlace!.formattedAddress}'),
Text('Rating: ${selectedPlace!.rating?.toString()}'),
// 根据需要添加更多地点信息
],
),
),
],
),
),
);
}
}
在这个示例中,我们创建了一个简单的Flutter应用,其中包含一个按钮,点击该按钮将打开一个地点选择器。用户可以选择一个地点,然后应用将显示所选地点的名称、地址和评分等信息。
请确保替换YOUR_API_KEY
为你的实际API密钥,并且在发布应用之前检查并遵守谷歌API的使用条款和条件。