Flutter地点选择插件places_picker的使用

Flutter地点选择插件places_picker的使用

简介

places_picker 是一个基于 Flutter 的插件,用于通过 Google Maps 实现地点选择功能。该项目依赖于以下包:

  • 使用 Flutter 官方的 google_maps_flutter 显示地图。
  • 使用 Baseflow 的 geolocator 获取当前位置。
  • 使用 hadrienlejard 的 google_maps_webservice 调用 Place 和 Geocoding API。
  • 使用 kevmoo 的 tuple 构建器。

预览

预览

支持

如果该插件对您有用或节省了您的时间,请不要犹豫,为我买一杯咖啡!😉
更多咖啡意味着未来我可以制作更有用的项目。

开始使用

获取 API 密钥

  1. Google Cloud Console 获取 API 密钥。
  2. 启用 Google Maps SDK for Android 和 iOS。

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。详细步骤如下:

  1. gradle.properties 文件中添加:
    android.useAndroidX=true
    android.enableJetifier=true
    
  2. android/app/build.gradle 文件中将 compileSdkVersion 设置为 28:
    android {
        compileSdkVersion 28
    
        ...
    }
    
  3. 将所有 android. 依赖替换为其对应的 AndroidX 版本(完整列表可在此处找到: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: [UIApplication.LaunchOptionsKey: 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 项目中启用 Location Updates 功能(项目 > 签名和能力 > “+” 按钮)。在 Info.plist 文件中添加以下键值对以启用嵌入式视图预览:

<key>io.flutter.embedded_views_preview</key>
<true/>

使用方法

基本用法

您可以使用 Navigator 推出一个新的页面,或者将其作为任何小部件的子级。当用户在地图上选择一个地点时,它会通过 onPlacePicked 回调返回结果,类型为 PickResult

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 参数说明

参数名称 类型 描述
placeId String 地点的唯一标识符,用于获取详细信息。
geometry Geometry 包含地点的几何信息,如位置和区域。
formattedAddress String 地址的人类可读形式,通常等同于邮政地址。
types List<String> 描述地点的特征类型数组。
addressComponents List<AddressComponent> 地址的单独组成部分数组。

PickResult 可选参数说明

参数名称 类型 描述
adrAddress String 地址的微格式表示。
formattedPhoneNumber String 地点的本地电话号码格式。
id String (未在 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。
scope String (未记录)
url String 地点的官方 Google 页面 URL。
vicinity String 地点的简化地址,包括街道名称、编号和城市,但不包括省/州、邮编或国家。
utcOffset num 此地当前时区相对于 UTC 的分钟数。
website String 地点的权威网站。
reviews List<Review> 最多五条评论的 JSON 数组。

自定义选择地点的可视化效果

默认情况下,当用户通过自动完成搜索或拖动地图选择地点时,信息会显示在屏幕底部(FloatingCard)。

如果您不喜欢这种 UI/UX,可以使用 selectedPlaceWidgetBuilder 覆盖默认构建器。您可以复用 FloatingCard 或创建自己的小部件。它与地图堆叠在一起,因此可能需要使用 Positioned 小部件。

注意: 使用此自定义选项不会触发 onPlacePicked 回调,因为它会覆盖默认的“选择这里”按钮。

PlacePicker(
  apiKey: APIKeys.apiKey,
  ...
  selectedPlaceWidgetBuilder: (_, selectedPlace, state, isSearchBarFocused) {
    return isSearchBarFocused
        ? Container()
        // 使用 FloatingCard 或创建自己的小部件。
        : FloatingCard(
            bottomPosition: 0.0,    // MediaQuery.of(context) 会导致重建。查看 MediaQuery 文档了解更多信息。
            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"); },),
         );
  },
  ...
),

selectedPlaceWidgetBuilder 参数说明

参数名称 类型 描述
context BuildContext Flutter 的构建上下文值。
selectedPlace PickResult 用户选择地点的结果数据。
state SearchingState 搜索操作的状态。(空闲、搜索中)
isSearchBarFocused bool 搜索栏是否当前聚焦,键盘是否显示。

自定义标记

默认情况下,标记图标具有简单的移动动画。但是,您也可以使用 pinBuilder 创建自己的标记小部件。

PlacePicker(
  apiKey: APIKeys.apiKey,
  ...
  pinBuilder: (context, state) {
        if (state == PinState.Idle) {
          return Icon(Icons.favorite_border);
        } else {
          return AnimatedIcon(.....);
        }
      },
  ...                        
),

pinBuilder 参数说明

参数名称 类型 描述
context BuildContext Flutter 的构建上下文值。
state PinState 标记的状态。(准备中、空闲、拖动中)

更改默认 FloatingCard 的颜色

虽然您可以构建自己的预测小部件,但仍然可以通过 themeData 修改默认小部件的样式。

Light 主题

final ThemeData lightTheme = ThemeData.light().copyWith(
  // FloatingCard 的背景颜色
  cardColor: Colors.white,
  buttonTheme: ButtonThemeData(
    // “选择这里”按钮的颜色
    buttonColor: Colors.black,
    textTheme: ButtonTextTheme.primary,
  ),
);

Dark 主题

final ThemeData darkTheme = ThemeData.dark().copyWith(
  // FloatingCard 的背景颜色
  cardColor: Colors.grey,
  buttonTheme: ButtonThemeData(
    // “选择这里”按钮的颜色
    buttonColor: Colors.yellow,
    textTheme: ButtonTextTheme.primary,
  ),
);

更多关于Flutter地点选择插件places_picker的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter地点选择插件places_picker的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


places_picker 是一个用于 Flutter 应用的地点选择插件,它允许用户从 Google Places API 中选择地点。使用这个插件,你可以轻松地集成地点选择功能到你的应用中。

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 places_picker 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  places_picker: ^0.0.1  # 请检查最新版本

然后运行 flutter pub get 来安装依赖。

2. 获取 Google Places API 密钥

要使用 places_picker,你需要一个 Google Places API 密钥。你可以在 Google Cloud Console 中创建一个项目并启用 Places API,然后生成 API 密钥。

3. 配置 Android 和 iOS

Android

android/app/src/main/AndroidManifest.xml 文件中添加以下代码:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.yourapp">
    <application
        android:label="Your App"
        android:icon="@mipmap/ic_launcher">
        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="YOUR_GOOGLE_PLACES_API_KEY"/>
    </application>
</manifest>

iOS

ios/Runner/Info.plist 文件中添加以下代码:

<key>NSLocationWhenInUseUsageDescription</key>
<string>We need your location to show nearby places.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>We need your location to show nearby places.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>We need your location to show nearby places.</string>
<key>GMSApiKey</key>
<string>YOUR_GOOGLE_PLACES_API_KEY</string>

4. 使用 places_picker

在你的 Flutter 代码中,你可以使用 places_picker 来启动地点选择器并获取用户选择的地点。

import 'package:flutter/material.dart';
import 'package:places_picker/places_picker.dart';

class PlacePickerExample extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Place Picker Example'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () async {
            // 启动地点选择器
            LocationResult result = await Navigator.of(context).push(
              MaterialPageRoute(
                builder: (context) => PlacePicker(
                  "YOUR_GOOGLE_PLACES_API_KEY",
                ),
              ),
            );

            // 处理选择的地点
            if (result != null) {
              print("Selected Place: ${result.formattedAddress}");
              print("Latitude: ${result.latLng.latitude}");
              print("Longitude: ${result.latLng.longitude}");
            }
          },
          child: Text('Pick a Place'),
        ),
      ),
    );
  }
}

void main() => runApp(MaterialApp(
  home: PlacePickerExample(),
));
回到顶部