Flutter地图渲染插件mapbox_gl_modified的使用

Flutter 地图渲染插件 mapbox_gl_modified 的使用

简介

此 Flutter 插件允许在 Flutter 小部件中嵌入交互式且可自定义的矢量地图。对于 Android 和 iOS 集成,我们使用了 mapbox-gl-native。对于 Web,我们依赖于 mapbox-gl-js。本项目仅支持这些库所暴露 API 的子集。

screenshot.png

设置

此包可以在 pub.dev 上找到。

通过运行以下命令将其添加到你的项目中:

flutter pub add mapbox_gl

移动端

秘密 Mapbox 访问令牌

为了使底层 Mapbox SDK 能够下载,需要一个具有 Downloads: Read 作用域的秘密访问令牌。更多信息可在 Mapbox 文档中找到:

如果未正确配置令牌,则构建过程会失败并出现以下错误(分别为 Android 和 iOS):

* What went wrong:
A problem occurred evaluating project ':mapbox_gl'.
> SDK Registry token is null. See README.md for more information.
[!] Error installing Mapbox-iOS-SDK
curl: (22) The requested URL returned error: 401 Unauthorized

Web

<head> 中包含 JavaScript 和 CSS 文件:

<script src='https://api.mapbox.com/mapbox-gl-js/v2.8.2/mapbox-gl.js'></script>
<link href='https://api.mapbox.com/mapbox-gl-js/v2.8.2/mapbox-gl.css' rel='stylesheet' />

<style>
   .mapboxgl-map {
      position: relative;
      width: 100%;
      height: 100%;
    }
</style>

注意:请查看最新的版本在 Mapbox GL JS 文档

所有平台

公共 Mapbox 访问令牌

需要为 MapboxMap 小部件提供公共访问令牌以检索样式和资源。虽然你可以直接将令牌硬编码到源文件中,但最好从外部源(如配置文件或环境变量)获取访问令牌。示例应用使用以下技术:

通过命令行参数传递访问令牌:

flutter build &lt;platform&gt; --dart-define ACCESS_TOKEN=YOUR_TOKEN_HERE

或运行应用程序时:

flutter run --dart-define ACCESS_TOKEN=YOUR_TOKEN_HERE

然后在 Dart 中获取它:

MapboxMap(
  ...
  accessToken: const String.fromEnvironment("ACCESS_TOKEN"),
  ...
)

支持的 API

特性 Android iOS Web
样式
相机
手势
用户位置
样式 DSL
栅格层
符号层
圆形层
线条层
填充层
填充拉伸层
高光层
热力图层
向量源
栅格源
GeoJSON 源
图像源
表达式
符号注解
圆形注解
线条注解
填充注解

地图样式

可以通过在 MapOptions 中设置 styleString 来提供地图样式。支持以下格式:

  1. 传递地图样式的 URL。这可以是内置的地图样式,也可以是使用 URL 开头为 ‘http(s)://’ 或 ‘mapbox://’ 远程服务的地图样式。
  2. 作为本地资源传递样式。在 assets 文件夹中创建一个 JSON 文件,并在 pubspec.yml 中添加引用。设置样式字符串为该资产的相对路径,以便将其加载到地图中。
  3. 作为本地文件传递样式。在应用程序目录中创建一个 JSON 文件(例如 ApplicationDocumentsDirectory)。设置样式字符串为该 JSON 文件的绝对路径。
  4. 传递原始地图样式的 JSON。这仅在 Android 上受支持。

离线地图侧载

通过侧载所需的地图瓦片并将它们包括在你的 assets 文件夹中,支持离线地图。

  1. 按照 此处 提供的指南创建你的瓦片包。
  2. 将第一步生成的 tiles.db 文件放置在你的 assets 目录中,并在 pubspec.yml 文件中添加引用。
assets:
  - assets/cache.db
  1. 在应用程序启动时调用 installOfflineMapTiles 方法,以将你的瓦片复制到 Mapbox 可以访问的位置。注意:此方法应在加载 Map 小部件之前调用,以防止在复制文件时发生冲突。
try {
  await installOfflineMapTiles(join("assets", "cache.db"));
} catch (err) {
  print(err);
}

下载离线区域

离线区域是一个定义的地图区域,在有限或无网络连接的情况下可供使用。使用适当的 SDK 方法从 Mapbox 下载选定区域、样式和精度的瓦片,并存储在应用程序的缓存中。

  1. 注意选择大区域可能会导致显著的大小。这里有一个在线估算器 https://docs.mapbox.com/playground/offline-estimator/
  2. 使用预定义的 OfflineRegion 调用 downloadOfflineRegionStream 并在回调函数中可选地跟踪进度。
final Function(DownloadRegionStatus event) onEvent = (DownloadRegionStatus status) {
  if (status.runtimeType == Success) {
    // ...
  } else if (status.runtimeType == InProgress) {
    int progress = (status as InProgress).progress.round();
    // ...
  } else if (status.runtimeType == Error) {
    // ...
  }
};

final OfflineRegion offlineRegion = OfflineRegion(
  bounds: LatLngBounds(
    northeast: LatLng(52.5050648, 13.3915634),
    southwest: LatLng(52.4943073, 13.4055383),
  ),
  id: 1,
  minZoom: 6,
  maxZoom: 18,
  mapStyleUrl: 'mapbox://styles/mapbox/streets-v11',
);

downloadOfflineRegionStream(offlineRegion, onEvent);

创建静态地图快照

snapshotManager 生成地图的静态栅格图像。每个快照图像由你提供的 SnapshotOptions 对象定义的地图部分组成。

调用 takeSnapshot 方法与预定义的 SnapshotOptions

final renderBox = mapKey.currentContext?.findRenderObject() as RenderBox;

final snapshotOptions = SnapshotOptions(
  width: renderBox.size.width,
  height: renderBox.size.height,
  writeToDisk: true,
  withLogo: false,
);

final uri = await mapController?.takeSnapshot(snapshotOptions);

定位功能

Android

<application>/android/app/src/main/AndroidManifest.xml 中添加 <code>&lt;uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /&gt;</code><code>&lt;uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /&gt;</code> 以启用 Android 应用程序中的定位功能。

从 Android API 级别 23 开始,还需要在运行时请求权限。此插件不会为你处理这一点。示例应用使用 flutter 的 'location' 插件 来处理这个问题。

iOS

要在 iOS 应用程序中启用定位功能:

如果你访问用户的位置,还应向 ios/Runner/Info.plist 添加以下键来解释为什么你需要访问他们的位置数据:

<key>NSLocationWhenInUseUsageDescription</key>
<string>[Your explanation here]</string>

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

1 回复

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


mapbox_gl_modified 是一个基于 Mapbox 的 Flutter 地图渲染插件,它允许开发者在 Flutter 应用中集成 Mapbox 地图,并支持自定义地图样式、添加标记、绘制路径等功能。这个插件是对 mapbox_gl 插件的修改版本,可能修复了一些问题或添加了一些额外功能。

1. 安装插件

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

dependencies:
  flutter:
    sdk: flutter
  mapbox_gl_modified: ^0.0.1  # 使用最新版本

然后运行 flutter pub get 来安装插件。

2. 获取 Mapbox 访问令牌

在使用 Mapbox 地图之前,你需要一个 Mapbox 访问令牌。你可以在 Mapbox 官网 注册并获取一个访问令牌。

3. 配置 Mapbox 访问令牌

在你的 Flutter 项目中,你需要在 AndroidiOS 项目中配置 Mapbox 访问令牌。

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.mapbox.token"
            android:value="YOUR_MAPBOX_ACCESS_TOKEN" />
        ...
    </application>
</manifest>

iOS 配置

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

<key>MGLMapboxAccessToken</key>
<string>YOUR_MAPBOX_ACCESS_TOKEN</string>

4. 使用 mapbox_gl_modified 插件

基本地图显示

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MapboxMapExample(),
    );
  }
}

class MapboxMapExample extends StatefulWidget {
  @override
  _MapboxMapExampleState createState() => _MapboxMapExampleState();
}

class _MapboxMapExampleState extends State<MapboxMapExample> {
  MapboxMapController? mapController;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Mapbox GL Modified Example')),
      body: MapboxMap(
        accessToken: 'YOUR_MAPBOX_ACCESS_TOKEN',
        onMapCreated: _onMapCreated,
        initialCameraPosition: CameraPosition(
          target: LatLng(37.7749, -122.4194), // 旧金山坐标
          zoom: 12.0,
        ),
      ),
    );
  }

  void _onMapCreated(MapboxMapController controller) {
    setState(() {
      mapController = controller;
    });
  }
}

添加标记

void _addMarker() async {
  if (mapController != null) {
    await mapController!.addMarker(
      MarkerOptions(
        geometry: LatLng(37.7749, -122.4194), // 旧金山坐标
        iconImage: 'assets/icon.png', // 标记图标
      ),
    );
  }
}

绘制路径

void _drawPolyline() async {
  if (mapController != null) {
    await mapController!.addPolyline(
      PolylineOptions(
        geometry: [
          LatLng(37.7749, -122.4194), // 起点
          LatLng(34.0522, -118.2437), // 终点
        ],
        color: '#FF0000', // 路径颜色
        width: 5.0, // 路径宽度
      ),
    );
  }
}

5. 处理地图事件

你可以监听地图的各种事件,例如点击、拖动等。

void _onMapCreated(MapboxMapController controller) {
  setState(() {
    mapController = controller;
  });

  controller.onMapClick.listen((point) {
    print('Map clicked at: ${point.latitude}, ${point.longitude}');
  });
}

6. 自定义地图样式

你可以使用 Mapbox Studio 创建自定义地图样式,并在 MapboxMap 组件中指定样式 URL。

MapboxMap(
  accessToken: 'YOUR_MAPBOX_ACCESS_TOKEN',
  onMapCreated: _onMapCreated,
  initialCameraPosition: CameraPosition(
    target: LatLng(37.7749, -122.4194), // 旧金山坐标
    zoom: 12.0,
  ),
  styleString: 'mapbox://styles/mapbox/streets-v11', // 自定义样式 URL
);
回到顶部