Flutter地图集成插件flutter_google_maps的使用

Flutter地图集成插件flutter_google_maps的使用

简介

Build Pub GitHub GitHub stars

flutter_google_maps 是一个用于在 iOS、Android 和 Web 应用程序中集成 Google 地图的 Flutter 插件。它是 google_maps_flutter(移动端)和 google_maps(Web)的封装。


开始使用

获取 API 密钥

  1. 访问 Google Cloud Console 获取 API 密钥。
  2. 启用 Google Maps SDK:
    • 选择项目。
    • 在导航菜单中选择“Google Maps”。
    • 启用“Maps SDK for Android”或“Maps SDK for iOS”。

Web 配置

<body>
  <script src="https://maps.googleapis.com/maps/api/js?key=API_KEY"></script>
  <script src="main.dart.js" type="application/javascript"></script>
</body>

Android 配置

android/app/src/main/AndroidManifest.xml 中添加以下内容:

<manifest ...
  <application ...
    <meta-data android:name="com.google.android.geo.API_KEY"
               android:value="YOUR KEY HERE"/>

iOS 配置

Objective-C

ios/Runner/AppDelegate.m 中添加以下内容:

#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

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)
  }
}

同时,在 Info.plist 中添加以下键值对:

<key>io.flutter.embedded_views_preview</key>
<string>YES</string>

集成 GoogleMap 小部件

初始化插件

main.dart 中初始化插件:

void main() {
  GoogleMap.init('API_KEY'); // 替换为你的 API 密钥
  WidgetsFlutterBinding.ensureInitialized();
  runApp(MyApp());
}

添加 GoogleMap 小部件

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

...

GlobalKey<GoogleMapStateBase> _key = GlobalKey<GoogleMapStateBase>();

@override
Widget build(BuildContext context) => GoogleMap(
      key: _key,
    );

...

示例代码

以下是完整的示例代码,展示如何配置和使用 flutter_google_maps 插件:

// Copyright (c) 2020, the MarchDev Toolkit project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_google_maps/flutter_google_maps.dart';

void main() {
  GoogleMap.init('API_KEY'); // 替换为你的 API 密钥
  WidgetsFlutterBinding.ensureInitialized();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Google Map Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _scaffoldKey = GlobalKey<ScaffoldState>();
  final _key = GlobalKey<GoogleMapStateBase>();
  bool _polygonAdded = false;
  bool _darkMapStyle = false;
  String _mapStyle;

  List<Widget> _buildClearButtons() => [
        RaisedButton.icon(
          color: Colors.red,
          textColor: Colors.white,
          icon: Icon(Icons.bubble_chart),
          label: Text('CLEAR POLYGONS'),
          onPressed: () {
            GoogleMap.of(_key).clearPolygons();
            setState(() => _polygonAdded = false);
          },
        ),
        const SizedBox(width: 16),
        RaisedButton.icon(
          color: Colors.red,
          textColor: Colors.white,
          icon: Icon(Icons.pin_drop),
          label: Text('CLEAR MARKERS'),
          onPressed: () {
            GoogleMap.of(_key).clearMarkers();
          },
        ),
        const SizedBox(width: 16),
        RaisedButton.icon(
          color: Colors.red,
          textColor: Colors.white,
          icon: Icon(Icons.directions),
          label: Text('CLEAR DIRECTIONS'),
          onPressed: () {
            GoogleMap.of(_key).clearDirections();
          },
        ),
      ];

  List<Widget> _buildAddButtons() => [
        FloatingActionButton(
          child: Icon(_polygonAdded ? Icons.edit : Icons.bubble_chart),
          backgroundColor: _polygonAdded ? Colors.orange : null,
          onPressed: () {
            if (!_polygonAdded) {
              GoogleMap.of(_key).addPolygon(
                '1',
                polygon,
                onTap: (polygonId) async {
                  await showDialog(
                    context: context,
                    builder: (context) => AlertDialog(
                      content: Text(
                        'This dialog was opened by tapping on the polygon!\n'
                        'Polygon ID is $polygonId',
                      ),
                      actions: <Widget>[
                        FlatButton(
                          onPressed: Navigator.of(context).pop,
                          child: Text('CLOSE'),
                        ),
                      ],
                    ),
                  );
                },
              );
            } else {
              GoogleMap.of(_key).editPolygon(
                '1',
                polygon,
                fillColor: Colors.purple,
                strokeColor: Colors.purple,
              );
            }

            setState(() => _polygonAdded = true);
          },
        ),
        const SizedBox(width: 16),
        FloatingActionButton(
          child: Icon(Icons.pin_drop),
          onPressed: () {
            GoogleMap.of(_key).addMarkerRaw(
              GeoCoord(33.875513, -117.550257),
              info: 'test info',
              onInfoWindowTap: () async {
                await showDialog(
                  context: context,
                  builder: (context) => AlertDialog(
                    content: Text(
                        'This dialog was opened by tapping on the InfoWindow!'),
                    actions: <Widget>[
                      FlatButton(
                        onPressed: Navigator.of(context).pop,
                        child: Text('CLOSE'),
                      ),
                    ],
                  ),
                );
              },
            );
            GoogleMap.of(_key).addMarkerRaw(
              GeoCoord(33.775513, -117.450257),
              icon: 'assets/images/map-marker-warehouse.png',
              info: contentString,
            );
          },
        ),
        const SizedBox(width: 16),
        FloatingActionButton(
          child: Icon(Icons.directions),
          onPressed: () {
            GoogleMap.of(_key).addDirection(
              'San Francisco, CA',
              'San Jose, CA',
              startLabel: '1',
              startInfo: 'San Francisco, CA',
              endIcon: 'assets/images/map-marker-warehouse.png',
              endInfo: 'San Jose, CA',
            );
          },
        ),
      ];

  @override
  Widget build(BuildContext context) => Scaffold(
        key: _scaffoldKey,
        appBar: AppBar(
          title: Text('Google Map'),
        ),
        body: Stack(
          children: <Widget>[
            Positioned.fill(
              child: GoogleMap(
                key: _key,
                markers: {
                  Marker(
                    GeoCoord(34.0469058, -118.3503948),
                  ),
                },
                initialZoom: 12,
                initialPosition:
                    GeoCoord(34.0469058, -118.3503948), // Los Angeles, CA
                mapType: MapType.roadmap,
                mapStyle: _mapStyle,
                interactive: true,
                onTap: (coord) =>
                    _scaffoldKey.currentState.showSnackBar(SnackBar(
                  content: Text(coord?.toString()),
                  duration: const Duration(seconds: 2),
                )),
                mobilePreferences: const MobileMapPreferences(
                  trafficEnabled: true,
                  zoomControlsEnabled: false,
                ),
                webPreferences: WebMapPreferences(
                  fullscreenControl: true,
                  zoomControl: true,
                ),
              ),
            ),
            Positioned(
              top: 16,
              left: 16,
              child: FloatingActionButton(
                child: Icon(Icons.person_pin_circle),
                onPressed: () {
                  final bounds = GeoCoordBounds(
                    northeast: GeoCoord(34.021307, -117.432317),
                    southwest: GeoCoord(33.835745, -117.712785),
                  );
                  GoogleMap.of(_key).moveCameraBounds(bounds);
                  GoogleMap.of(_key).addMarkerRaw(
                    GeoCoord(
                      (bounds.northeast.latitude + bounds.southwest.latitude) / 2,
                      (bounds.northeast.longitude + bounds.southwest.longitude) / 2,
                    ),
                    onTap: (markerId) async {
                      await showDialog(
                        context: context,
                        builder: (context) => AlertDialog(
                          content: Text(
                            'This dialog was opened by tapping on the marker!\n'
                            'Marker ID is $markerId',
                          ),
                          actions: <Widget>[
                            FlatButton(
                              onPressed: Navigator.of(context).pop,
                              child: Text('CLOSE'),
                            ),
                          ],
                        ),
                      );
                    },
                  );
                },
              ),
            ),
            Positioned(
              top: 16,
              right: kIsWeb ? 60 : 16,
              child: FloatingActionButton(
                onPressed: () {
                  if (_darkMapStyle) {
                    GoogleMap.of(_key).changeMapStyle(null);
                    _mapStyle = null;
                  } else {
                    GoogleMap.of(_key).changeMapStyle(darkMapStyle);
                    _mapStyle = darkMapStyle;
                  }

                  setState(() => _darkMapStyle = !_darkMapStyle);
                },
                backgroundColor: _darkMapStyle ? Colors.black : Colors.white,
                child: Icon(
                  _darkMapStyle ? Icons.wb_sunny : Icons.brightness_3,
                  color: _darkMapStyle ? Colors.white : Colors.black,
                ),
              ),
            ),
            Positioned(
              left: 16,
              right: kIsWeb ? 60 : 16,
              bottom: 16,
              child: Row(
                children: <Widget>[
                  LayoutBuilder(
                    builder: (context, constraints) =>
                        constraints.maxWidth < 1000
                            ? Row(children: _buildClearButtons())
                            : Column(
                                crossAxisAlignment: CrossAxisAlignment.start,
                                children: _buildClearButtons(),
                              ),
                  ),
                  Spacer(),
                  ..._buildAddButtons(),
                ],
              ),
            ),
          ],
        ),
      );
}

const darkMapStyle = r'''
[
  {
    "elementType": "geometry",
    "stylers": [
      {
        "color": "#212121"
      }
    ]
  },
  {
    "elementType": "labels.icon",
    "stylers": [
      {
        "visibility": "off"
      }
    ]
  },
  {
    "elementType": "labels.text.fill",
    "stylers": [
      {
        "color": "#757575"
      }
    ]
  },
  {
    "elementType": "labels.text.stroke",
    "stylers": [
      {
        "color": "#212121"
      }
    ]
  },
  ...
];
''';

const contentString = r'''
<div id="content">
  <div id="siteNotice"></div>
  <h1 id="firstHeading" class="firstHeading">Uluru</h1>
  <div id="bodyContent">
    <p>
      <b>Uluru</b>, also referred to as <b>Ayers Rock</b>, is a large 
      sandstone rock formation in the southern part of the 
      Northern Territory, central Australia. It lies 335&#160;km (208&#160;mi) 
      south west of the nearest large town, Alice Springs; 450&#160;km 
      (280&#160;mi) by road. Kata Tjuta and Uluru are the two major 
      features of the Uluru - Kata Tjuta National Park. Uluru is 
      sacred to the Pitjantjatjara and Yankunytjatjara, the 
      Aboriginal people of the area. It has many springs, waterholes, 
      rock caves and ancient paintings. Uluru is listed as a World 
      Heritage Site.
    </p>
    <p>
      Attribution: Uluru, 
      <a href="http://en.wikipedia.org/w/index.php?title=Uluru&amp;oldid=297882194">
        http://en.wikipedia.org/w/index.php?title=Uluru
      </a>
      (last visited June 22, 2009).
    </p>
  </div>
</div>
''';

const polygon = [
  GeoCoord(32.707868, -117.191018),
  GeoCoord(32.705645, -117.191096),
  GeoCoord(32.697756, -117.166664),
  GeoCoord(32.686486, -117.163206),
  GeoCoord(32.675876, -117.169452),
  GeoCoord(32.674726, -117.165233),
  GeoCoord(32.679833, -117.158487),
  GeoCoord(32.677571, -117.153893),
  GeoCoord(32.671987, -117.160079),
  GeoCoord(32.667547, -117.160477),
  GeoCoord(32.654748, -117.147579),
  GeoCoord(32.651933, -117.150312),
  GeoCoord(32.649676, -117.144334),
  GeoCoord(32.631665, -117.138201),
  GeoCoord(32.632033, -117.132249),
  GeoCoord(32.630156, -117.137234),
  GeoCoord(32.628072, -117.136479),
  GeoCoord(32.630315, -117.131443),
  GeoCoord(32.625930, -117.135312),
  GeoCoord(32.623754, -117.131664),
  GeoCoord(32.627465, -117.130883),
  GeoCoord(32.622598, -117.128791),
  GeoCoord(32.622622, -117.133183),
  GeoCoord(32.618690, -117.133634),
  GeoCoord(32.618980, -117.128403),
  GeoCoord(32.609847, -117.132502),
  GeoCoord(32.604198, -117.125333),
  GeoCoord(32.588260, -117.122032),
  GeoCoord(32.591164, -117.116851),
  GeoCoord(32.587601, -117.105968),
  GeoCoord(32.583792, -117.104434),
  GeoCoord(32.570566, -117.101382),
  GeoCoord(32.569256, -117.122378),
  GeoCoord(32.560825, -117.122903),
  GeoCoord(32.557753, -117.131040),
  GeoCoord(32.542737, -117.124883),
  GeoCoord(32.534156, -117.126062),
  GeoCoord(32.563255, -117.134963),
  GeoCoord(32.584055, -117.134263),
  GeoCoord(32.619405, -117.140001),
  GeoCoord(32.655293, -117.157349),
  GeoCoord(32.669944, -117.169624),
  GeoCoord(32.682710, -117.189445),
  GeoCoord(32.685297, -117.208773),
  GeoCoord(32.679814, -117.224882),
  GeoCoord(32.697212, -117.227058),
  GeoCoord(32.707701, -117.219816),
  GeoCoord(32.711931, -117.214107),
  GeoCoord(32.715026, -117.196521),
  GeoCoord(32.713053, -117.189703),
  GeoCoord(32.707868, -117.191018),
];

属性说明

GoogleMap 小部件支持的属性

属性名称 类型 描述
initialPosition GeoCoord 地图初始中心位置
initialZoom double 初始缩放级别
mapType MapType 地图类型(普通、卫星、地形等)
minZoom double 最小缩放级别
maxZoom double 最大缩放级别
mapStyle String 地图样式
mobilePreferences MobileMapPreferences 移动端地图偏好设置
webPreferences WebMapPreferences Web 端地图偏好设置
interactive bool 是否允许交互
onTap ValueChanged 地图点击事件
onLongPress ValueChanged 地图长按事件
markers Set 地图标记

MapType 枚举

描述
none 不显示地图瓦片
roadmap 普通瓦片(交通和标签,轻微地形信息)
satellite 卫星影像瓦片(航拍照片)
terrain 地形瓦片(指示地形类型和高度)
hybrid 混合瓦片(卫星图像与一些标签/叠加层)

MobileMapPreferences 支持的属性

属性名称 类型 描述
compassEnabled bool 是否显示指南针
mapToolbarEnabled bool 是否显示工具栏(仅限 Android)
myLocationEnabled bool 是否显示“我的位置”图层
myLocationButtonEnabled bool 是否启用“我的位置”按钮
indoorViewEnabled bool 是否启用室内视图
trafficEnabled bool 是否启用交通图层
buildingsEnabled bool 是否显示可用的 3D 建筑物
padding EdgeInsets 地图细节的填充
rotateGesturesEnabled bool 是否响应旋转手势
scrollGesturesEnabled bool 是否响应滚动手势
zoomGesturesEnabled bool 是否响应缩放手势
tiltGesturesEnabled bool 是否响应倾斜手势

WebMapPreferences 支持的属性

属性名称 类型 描述
streetViewControl bool 是否启用街景控件
fullscreenControl bool 是否启用全屏控件
mapTypeControl bool 是否启用地图类型控件
scrollwheel bool 是否启用滚轮缩放
panControl bool 是否启用平移控件
overviewMapControl bool 是否启用概览地图控件
rotateControl bool 是否启用旋转控件
scaleControl bool 是否启用比例尺控件
zoomControl bool 是否启用缩放控件
dragGestures bool 是否启用拖动手势

与 GoogleMap 交互

使用静态方法 of

示例:移动相机到新边界

void moveCameraBounds(
  GeoCoordBounds newBounds, {
  double padding = 0,
  bool animated = true,
  bool waitUntilReady = true,
});

示例:移动相机到新坐标

void moveCamera(
  GeoCoord latLng, {
  bool animated = true,
  bool waitUntilReady = true,
  double zoom,
});

示例:获取地图中心坐标

FutureOr<GeoCoord> get center;

示例:改变地图样式

void changeMapStyle(String mapStyle);

示例:添加标记

void addMarkerRaw(
  GeoCoord position, {
  String label,
  String icon,
  String info,
  ValueChanged<String> onTap,
  VOidCallback onInfoWindowTap,
});

示例:删除所有标记

void clearMarkers();

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

1 回复

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


flutter_google_maps 是一个用于在 Flutter 应用中集成 Google 地图的插件。它允许你在应用中显示地图、添加标记、处理用户交互等。以下是如何使用 flutter_google_maps 插件的基本步骤:

1. 添加依赖

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

dependencies:
  flutter:
    sdk: flutter
  flutter_google_maps: ^latest_version

然后运行 flutter pub get 来获取依赖。

2. 获取 Google Maps API 密钥

要使用 Google 地图,你需要一个 Google Maps API 密钥。你可以通过以下步骤获取:

  1. 访问 Google Cloud Console
  2. 创建一个新项目或选择现有项目。
  3. 启用 Maps SDK for AndroidMaps SDK for iOS
  4. 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>
        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="YOUR_ANDROID_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_IOS_API_KEY")
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

4. 使用 GoogleMap 组件

在你的 Flutter 应用中使用 GoogleMap 组件来显示地图。以下是一个简单的示例:

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Google Maps Example'),
        ),
        body: GoogleMap(
          initialPosition: GeoCoord(37.7749, -122.4194), // 初始位置(旧金山)
          mapType: MapType.normal,
          markers: {
            Marker(
              markerId: MarkerId('marker_1'),
              position: GeoCoord(37.7749, -122.4194),
              infoWindow: InfoWindow(title: 'San Francisco'),
            ),
          },
          onMapCreated: (GoogleMapController controller) {
            // 地图创建完成后的回调
          },
        ),
      ),
    );
  }
}
回到顶部