Flutter地图展示插件arcgis_maps的使用
Flutter地图展示插件arcgis_maps的使用
使用ArcGIS Maps SDK for Flutter构建原生移动应用,可以集成诸如2D数据可视化和编辑、地理编码和路由等功能,并部署到iOS或Android平台。
平台支持
- 使用macOS开发主机来部署到iOS和Android移动设备。
- 使用Windows开发主机来部署到Android移动设备。
有关更多信息,请参阅我们的详细系统需求。
功能
ArcGIS Maps SDK for Flutter的第一个版本不包括其他ArcGIS Maps SDKs for Native Apps的所有API和功能。这些缺失的功能将在后续版本中引入。更多详细信息,请查看我们的API对等页面。
开始使用
在您的应用程序中添加arcgis_maps
作为依赖项后,运行以下命令以下载并安装arcgis_maps_core
:
dart run arcgis_maps install
注意:在Windows上,这一步骤需要创建符号链接的权限。您可以以管理员身份运行此步骤,或者转到“设置 > 更新与安全 > 开发者选项”,并打开“开发者模式”。
然后将arcgis_maps_core
添加到您的.gitignore
文件中:
# 杂项
arcgis_maps_core
...
更多信息,请参阅我们的安装和设置指南。
如果您是Flutter开发的新手或初次接触ArcGIS,请查看我们的详细入门指南。
平台特定配置
Android
通过编辑android/app/build.gradle
文件来更新最低要求:
- 设置Android NDK 25.2.9519653为最低版本
- 设置Android SDK 26为最低版本
android {
...
ndkVersion "25.2.9519653"
...
defaultConfig {
...
minSdk 26
...
}
...
}
通过编辑android/settings.gradle
文件来更新Kotlin版本:
- 将Kotlin版本设置为1.9.0
plugins {
...
id "org.jetbrains.kotlin.android" version "1.9.0" apply false
}
iOS
通过编辑ios/Podfile
文件来设置iOS 16.0为最低版本。首先取消注释该行,然后更新版本号。
platform :ios, '16.0'
通过添加Runtimecore
和arcgis_maps_ffi
Pod到Runner
目标部分来配置arcgis_maps_core
:
target 'Runner' do
...
pod 'Runtimecore', :podspec => '../arcgis_maps_core/ios/Runtimecore.podspec'
pod 'arcgis_maps_ffi', :podspec => '../arcgis_maps_core/ios/arcgis_maps_ffi.podspec'
...
end
使用pod update
来配置Pods:
cd ios && pod update && cd ..
额外权限
一些ArcGIS Maps SDK for Flutter的功能在部署应用程序时需要额外的密钥和权限。有关更多信息,请参阅我们的详细安装和设置指南。
使用API
在小部件树中添加一个ArcGISMapView
,分配一个ArcGISMapViewController
并应用一个ArcGISMap
。
...
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
body: ArcGISMapView(
controllerProvider: () => ArcGISMapView.createController()
..arcGISMap = ArcGISMap.withBasemapStyle(BasemapStyle.arcGISImagery),
),
);
}
...
有关信息和可用类列表,请参阅我们的API参考。
我们还提供了示例代码,演示了ArcGIS Maps SDK for Flutter的功能以及如何在您的应用程序中使用它们,以及教程,提供逐步指导以构建包含ArcGIS Maps功能的应用程序。
API密钥认证
上述示例代码使用了可以通过API密钥访问的ArcGIS Location Platform底图。要获取访问令牌,请参阅我们的入门指南。
如果您已经有访问令牌,请将其设置在应用程序的main()
方法中:
void main() {
ArcGISEnvironment.apiKey = 'YOUR_ACCESS_TOKEN';
...
}
其他资源
- 新手?探索我们的文档:指南 | API参考
- 新手?查看我们的入门指南
- 示例代码:演示ArcGIS Maps SDK for Flutter的功能及如何在您的应用程序中使用它们。
- 教程:提供逐步指导以构建包含ArcGIS Maps功能的应用程序。
- 功能和API对等性
- 有问题?在我们的论坛上提问。
示例代码
//
// COPYRIGHT © 2023 Esri
//
// All rights reserved under the copyright laws of the United States
// and applicable international laws, treaties, and conventions.
//
// This material is licensed for use under the Esri Master
// Agreement (MA) and is bound by the terms and conditions
// of that agreement.
//
// You may redistribute and use this code without modification,
// provided you adhere to the terms and conditions of the MA
// and include this copyright notice.
//
// See use restrictions at http://www.esri.com/legal/pdfs/mla_e204_e300/english
//
// For additional information, contact:
// Environmental Systems Research Institute, Inc.
// Attn: Contracts and Legal Department
// 380 New York Street
// Redlands, California 92373
// USA
//
// email: legal@esri.com
//
import 'package:arcgis_maps/arcgis_maps.dart';
import 'package:flutter/material.dart';
void main() async {
// 通过命令行参数 --dart-define-from-file 提供您的apiKey。
const apiKey = String.fromEnvironment('API_KEY');
// 或者替换上面的行并在这里硬编码您的apiKey:
// const apiKey = ''; // 您的API Key在这里。
if (apiKey.isEmpty) {
throw Exception('apiKey undefined');
} else {
ArcGISEnvironment.apiKey = apiKey;
}
// ArcGISMapsExample 是此示例应用程序的主要小部件。
runApp(const MaterialApp(home: ArcGISMapsExample()));
}
/// ArcGISMapsExample 演示如何使用 arcgis_maps 构建基本的2D映射应用程序。
/// 此应用程序:
/// - 创建并显示了一个 [ArcGISMapView] 小部件及其 [ArcGISMapViewController]。
/// - 设置了一个 [ArcGISMap] 到 [ArcGISMapViewController.arcGISMap]。
/// - 向 [ArcGISMap.operationalLayers] 添加了一组 [FeatureLayer]。
/// - 向 [ArcGISMapViewController.graphicsOverlays] 添加了一个 [GraphicsOverlay]。
/// - 配置了一个 [GeometryEditor] 以创建新的 [Graphic] 并添加到 [GraphicsOverlay.graphics]。
class ArcGISMapsExample extends StatefulWidget {
const ArcGISMapsExample({super.key});
[@override](/user/override)
State<ArcGISMapsExample> createState() => _ArcGISMapsExampleState();
}
class _ArcGISMapsExampleState extends State<ArcGISMapsExample> {
// 创建一个用于地图视图的控制器。
final _mapViewController = ArcGISMapView.createController();
// 创建一个具有底图样式的地图。
final _map = ArcGISMap.withBasemapStyle(BasemapStyle.arcGISImageryStandard);
// 创建一个用于显示图形的图形覆盖层。
final _graphicsOverlay = GraphicsOverlay();
// 创建一个几何编辑器以创建新几何图形。
final _geometryEditor = GeometryEditor();
// 一个标志,指示UI是否准备好使用。
var _ready = false;
// 一个标志,基于编辑是否正在进行来控制UI。
var _editingInProgress = false;
// 一个标志,基于图层可见性来控制UI。
var _layersVisible = true;
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
top: false,
child: Stack(
children: [
Column(
children: [
Expanded(
// 在小部件树中添加一个 ArcGISMapView 小部件,并设置一个控制器。
child: ArcGISMapView(
controllerProvider: () => _mapViewController,
// 配置当地图视图准备就绪时的操作。
onMapViewReady: onMapViewReady,
// 配置用户点击地图视图小部件时的操作。
onTap: !_editingInProgress ? onTap : null,
),
),
],
),
// 添加按钮到UI以切换图层可见性和创建新图形。
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: const EdgeInsets.only(bottom: 30.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Tooltip(
message: '切换图层可见性',
child: ElevatedButton(
onPressed: _ready ? toggleLayerVisibility : null,
child: Icon(
_layersVisible
? Icons.visibility
: Icons.visibility_off,
),
),
),
Tooltip(
message: '创建一个新的图形',
child: ElevatedButton(
onPressed: _ready
? _editingInProgress
? saveEdits
: startEditing
: null,
child: Icon(
_editingInProgress ? Icons.save : Icons.draw,
),
),
),
],
),
),
],
),
],
),
),
);
}
void onMapViewReady() async {
// 使用 ArcGISOnline 门户和所需项目ID和图层数创建特征层。
final arcGISOnlinePortal = Portal.arcGISOnline();
final buildings = FeatureLayer.withFeatureLayerItem(
PortalItem.withPortalAndItemId(
portal: arcGISOnlinePortal,
itemId: '0ec8512ad21e4bb987d7e848d14e7e24',
),
);
final primaryRoads = FeatureLayer.withItem(
item: PortalItem.withPortalAndItemId(
portal: arcGISOnlinePortal,
itemId: 'f42ecc08a3634182b8678514af35fac3',
),
layerId: 2,
);
final secondaryRoads = FeatureLayer.withItem(
item: PortalItem.withPortalAndItemId(
portal: arcGISOnlinePortal,
itemId: 'f42ecc08a3634182b8678514af35fac3',
),
layerId: 6,
);
final localRoads = FeatureLayer.withItem(
item: PortalItem.withPortalAndItemId(
portal: arcGISOnlinePortal,
itemId: 'f42ecc08a3634182b8678514af35fac3',
),
layerId: 8,
);
// 将图层添加到地图的操作层。
_map.operationalLayers
.addAll([buildings, primaryRoads, secondaryRoads, localRoads]);
// 定义一个渲染器以样式化任何添加到图形覆盖层中的图形。
_graphicsOverlay.renderer = SimpleRenderer(
symbol: SimpleFillSymbol(
style: SimpleFillSymbolStyle.solid,
color: Colors.cyanAccent.withOpacity(0.4),
outline: SimpleLineSymbol(
style: SimpleLineSymbolStyle.dash,
color: Colors.cyan,
width: 2,
),
),
);
// 添加一些初始图形以在启动时显示。
_graphicsOverlay.graphics.addAll(createGraphics());
// 将图形覆盖层添加到地图视图控制器以显示它。
_mapViewController.graphicsOverlays.add(_graphicsOverlay);
// 分配地图到地图视图控制器。
_mapViewController.arcGISMap = _map;
// 设置一个初始视点以在启动时显示。
_mapViewController.setViewpoint(
Viewpoint.fromCenter(
ArcGISPoint(
x: -13310927.924,
y: 4367840.399,
),
scale: 5000,
),
);
// 分配几何编辑器到地图视图控制器。
_mapViewController.geometryEditor = _geometryEditor;
// 配置一些几何编辑器设置。
await configureGeometryEditor();
// 完成所有配置后启用UI。
setState(() => _ready = true);
}
void onTap(Offset offset) async {
// 在地图视图小部件上的点击屏幕点执行识别操作。
final identifyGraphicsOverlayResult =
await _mapViewController.identifyGraphicsOverlay(
_graphicsOverlay,
screenPoint: offset,
tolerance: 22.0,
);
// 如果在点击位置识别到图形,则显示对话框。
if (identifyGraphicsOverlayResult.graphics.isNotEmpty) {
final identifiedGraphic = identifyGraphicsOverlayResult.graphics.first;
if (mounted) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
alignment: Alignment.center,
title: const Text('点击了图形'),
content: Text(
'中心点:\n'
'x: ${identifiedGraphic.geometry?.extent.center.x}\n'
'y: ${identifiedGraphic.geometry?.extent.center.y}',
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('确定'),
),
],
);
},
);
}
}
}
// 创建一个初始图形列表以显示。
List<Graphic> createGraphics() {
const largePolygonJson = '''
{"rings":[[[-13311062.662636876,4368080.2952499595],[-13311057.127783449,4368076.3178643389],
[-13311061.634682227,4367769.666227323],[-13311103.149254397,4367767.9142679712],
[-13311104.043995325,4367698.8852444943],[-13311091.295635514,4367692.5083970781],
[-13311089.376387239,4367666.5662346007],[-13311068.132243464,4367666.3481658408],
[-13311067.365961147,4367656.5642296085],[-13311058.564161845,4367655.1021004347],
[-13311060.260100655,4367569.1472102059],[-13311314.397355149,4367569.6304349722],
[-13311329.11803535,4367581.7673969641],[-13311325.279430484,4368078.8186992826],
[-13311229.822984351,4368080.2299739141],[-13311228.715676585,4367907.4899566751],
[-13311146.872602904,4367905.7258633124],[-13311145.543586506,4368081.7248991122],
[-13311062.662636876,4368080.2952499595]]],
"spatialReference":{"latestWkid":3857,"wkid":102100}}''';
// 使用提供的JSON字符串创建多边形几何。
final largePolygonGeometry = Geometry.fromJsonString(largePolygonJson);
// 使用几何创建一个新的图形。
final largeGraphic = Graphic(geometry: largePolygonGeometry);
const mediumPolygonJson = '''
{"rings":[[[-13310930.109359179,4367955.6946535213],[-13310939.951467492,4367565.1394895678],
[-13311052.146218125,4367566.2247806583],[-13311050.523812089,4367957.6713874312],
[-13310930.109359179,4367955.6946535213]]],
"spatialReference":{"latestWkid":3857,"wkid":102100}}''';
// 使用提供的JSON字符串创建多边形几何。
final mediumPolygonGeometry = Geometry.fromJsonString(mediumPolygonJson);
// 使用几何创建一个新的图形。
final mediumGraphic = Graphic(geometry: mediumPolygonGeometry);
const smallPolygonJson = '''
{"rings":[[[-13311036.736801982,4368106.8208614551],[-13311035.197346671,4368240.6001734752],
[-13310765.222839184,4368239.1766897719],[-13310763.479211008,4368109.3070116714],
[-13311036.736801982,4368106.8208614551]]],
"spatialReference":{"latestWkid":3857,"wkid":102100}}''';
// 使用提供的JSON字符串创建多边形几何。
final smallPolygonGeometry = Geometry.fromJsonString(smallPolygonJson);
// 使用几何创建一个新的图形。
final smallGraphic = Graphic(geometry: smallPolygonGeometry);
return [largeGraphic, mediumGraphic, smallGraphic];
}
// 配置一些几何编辑器设置。
Future<void> configureGeometryEditor() async {
// 使用光标顶点工具。
_geometryEditor.tool = ReticleVertexTool();
// 设置地图的特征分块模式。
// 为了确保数据完整性,编辑时需要全分辨率的捕捉。
_map.loadSettings.featureTilingMode =
FeatureTilingMode.enabledWithFullResolutionWhenSupported;
// 确保地图和每个图层按顺序加载以同步捕捉设置。
await _map.load();
await Future.wait(_map.operationalLayers.map((layer) => layer.load()));
// 启用几何编辑器的捕捉。
_geometryEditor.snapSettings.isEnabled = true;
_geometryEditor.snapSettings.isGeometryGuidesEnabled = true;
// 将图形覆盖层和特征层添加到捕捉源,并为每个源启用捕捉。
_geometryEditor.snapSettings.syncSourceSettings();
for (final snapSourceSetting
in _geometryEditor.snapSettings.sourceSettings) {
snapSourceSetting.isEnabled = true;
}
}
// 开始几何编辑器以创建新几何图形。
void startEditing() {
// 使用多边形几何类型开始几何编辑器以创建新的多边形几何图形。
_geometryEditor.startWithGeometryType(GeometryType.polygon);
setState(() => _editingInProgress = true);
}
// 保存由几何编辑器创建的几何图形到图形覆盖层。
void saveEdits() {
// 停止几何编辑器并获取返回的几何图形。
final geometry = _geometryEditor.stop();
setState(() => _editingInProgress = false);
if (geometry != null) {
// 如果有有效的几何图形,使用它创建一个新的图形。
final graphic = Graphic(geometry: geometry);
// 将图形添加到图形覆盖层。
_graphicsOverlay.graphics.add(graphic);
}
}
// 切换地图的操作层的可见性。
void toggleLayerVisibility() {
setState(() => _layersVisible = !_layersVisible);
if (_mapViewController.arcGISMap != null) {
// 获取地图的操作层列表中的每个图层并切换其 isVisible 属性。
for (final layer in _mapViewController.arcGISMap!.operationalLayers) {
layer.isVisible = _layersVisible;
}
}
}
}
更多关于Flutter地图展示插件arcgis_maps的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter地图展示插件arcgis_maps的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个使用 arcgis_maps
插件在 Flutter 中展示地图的基本示例。这个插件允许你在 Flutter 应用中嵌入和展示 ArcGIS 地图。
首先,确保你已经在 pubspec.yaml
文件中添加了 arcgis_maps
依赖:
dependencies:
flutter:
sdk: flutter
arcgis_maps: ^latest_version # 请替换为最新的版本号
然后运行 flutter pub get
来获取依赖。
接下来,在你的 Flutter 项目中,你可以创建一个简单的页面来展示 ArcGIS 地图。以下是一个完整的示例代码:
import 'package:flutter/material.dart';
import 'package:arcgis_maps/arcgis_maps.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'ArcGIS Map Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: ArcGISMapScreen(),
);
}
}
class ArcGISMapScreen extends StatefulWidget {
@override
_ArcGISMapScreenState createState() => _ArcGISMapScreenState();
}
class _ArcGISMapScreenState extends State<ArcGISMapScreen> {
// ArcGIS MapView Controller
late ArcGISMapViewController _mapViewController;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ArcGIS Map Example'),
),
body: ArcGISMapView(
// Provide your ArcGIS API key here
apiKey: 'YOUR_ARCGIS_API_KEY',
onMapViewInitialized: (ArcGISMapViewController controller) {
_mapViewController = controller;
// Optionally, set the initial map viewpoint
_setViewpoint();
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// Example: Zoom to a specific location
_zoomToLocation();
},
tooltip: 'Zoom to Location',
child: Icon(Icons.zoom_in),
),
);
}
void _setViewpoint() {
// Define the initial viewpoint (e.g., centered on a specific location)
final Viewpoint centerAt = Viewpoint(
targetGeometry: Envelope(
xmin: -122.45,
ymin: 37.75,
xmax: -122.4,
ymax: 37.8,
spatialReference: SpatialReference(wkid: 4326), // WGS 84
),
scale: 50000, // Define the scale
);
_mapViewController.setViewpoint(centerAt);
}
void _zoomToLocation() {
// Define a new viewpoint to zoom to
final Viewpoint newViewpoint = Viewpoint(
targetGeometry: Point(
x: -122.4324,
y: 37.7749,
spatialReference: SpatialReference(wkid: 4326), // WGS 84
),
scale: 20000, // Define the new scale
);
_mapViewController.setViewpoint(newViewpoint);
}
}
注意事项:
-
API Key: 你需要在
ArcGISMapView
的apiKey
属性中提供有效的 ArcGIS API 密钥。你可以通过注册 ArcGIS 开发者账户并创建一个新的应用来获取这个密钥。 -
依赖版本: 确保你使用的是
arcgis_maps
插件的最新版本。你可以在 pub.dev 上查找最新的版本信息。 -
地图初始化: 在
onMapViewInitialized
回调中,你可以获取ArcGISMapViewController
实例,用于控制地图视图(例如设置视点和缩放级别)。 -
空间参考系: 在定义地理位置时,确保使用正确的空间参考系(例如 WGS 84,其 wkid 为 4326)。
这个示例展示了如何使用 arcgis_maps
插件在 Flutter 应用中嵌入和展示 ArcGIS 地图,并包含了一些基本的交互操作,如设置初始视点和缩放到特定位置。你可以根据具体需求进一步扩展和自定义地图功能。