Flutter地图集成与测试调试全解析
1. 向地图添加标记
在应用程序中显示地图只是创建基于地图应用的起点。添加地点信息是处理地图时最常见的任务之一。我们可以使用插件提供的 Marker 类向之前创建的地图添加标记。
1.1 Marker类
根据文档, Marker 只是在地图上标记一个地理位置。它在地图上添加上下文信息,例如识别一个地点、检查点或兴趣点。标记通常使用图标定义,并在其点击事件中包含单个或多个操作。在向地图添加标记时,以下属性是最常用的:
- position :虽然插件本身不强制要求,但它标识标记在地图上的地理位置,因此几乎总是需要的。
- icon :这是 BitmapDescriptor 格式的标记图标。更多关于 BitmapDescriptor 类的信息,请查看插件文档页面: https://pub.dartlang.org/documentation/google_maps_flutter/latest/google_maps_flutter/BitmapDescriptor-class.html 。
- markerId :这是地图上标记的唯一标识符。
- infoWindow :这是点击标记时显示的Google地图信息窗口。
文档提示:“标记图标是相对于设备屏幕绘制的,而不是地图表面,也就是说,它不会因地图旋转、倾斜或缩放而改变方向。”
1.2 在GoogleMap小部件中添加标记
GoogleMap 小部件公开了 markers 属性,该属性期望传入一个 Marker 实例的 Set 集合。以下是通过设置 markers 属性添加标记的步骤:
1. 首先,在 MapPage 类中添加一个 _markers 字段来保存一组随机标记( Marker 实例):
class MapPage extends StatelessWidget {
final _markers = {
Marker(
position: LatLng(51.178883, -1.826215),
markerId: MarkerId('1'),
infoWindow: InfoWindow(title: 'Stonehenge'),
icon: BitmapDescriptor.defaultMarker
),
Marker(
position: LatLng(41.890209, 12.492231),
markerId: MarkerId('2'),
infoWindow: InfoWindow(title: 'Colosseum'),
icon: BitmapDescriptor.defaultMarker
),
Marker(
position: LatLng(36.106964, -112.112999),
markerId: MarkerId('3'),
infoWindow: InfoWindow(title: 'Grand Canyon'),
icon: BitmapDescriptor.defaultMarker
),
};
...
}
- 然后,在
GoogleMap小部件上设置markers属性:
@override
Widget build(BuildContext context) {
return GoogleMap(
initialCameraPosition:
CameraPosition(target: LatLng(51.178883, -1.826215),
zoom: 10.0),
markers: _markers,
);
}
点击标记时,会显示相应的 InfoWindow 对象,并显示设置的标题。
向 GoogleMap 小部件添加标记就像显示地图本身一样简单,它遵循Flutter的范式,即使用构造函数中提供的描述重建小部件(即标记)。
2. 添加地图交互
向地图添加标记有助于丰富其中的上下文信息,但对于真正的基于地图的应用来说,这远远不够。处理事件或根据用户需求更改地图也是至关重要的。我们将学习如何动态地向地图添加标记,并使用 GoogleMapController 类以编程方式与地图相机进行交互。
2.1 动态添加标记
由于需要在 GoogleMap 小部件构建期间传递标记,因此第一步是将 MapPage 小部件变为 StatefulWidget ,并在每次添加新标记时重建其子树。
之后,需要在布局中添加一个按钮,以便在初始构建后添加标记。按钮的 onPressed 回调调用 _addMarkerOnCameraCenter 方法,如下所示:
void _addMarkerOnCameraCenter() {
setState(() {
_markers.add(Marker(
markerId: MarkerId("${_markers.length + 1}"),
infoWindow: InfoWindow(title: "Added marker"),
icon: BitmapDescriptor.defaultMarker,
position: _cameraCenter,
));
});
}
这里使用 setState 方法触发小部件的重建,并将 Marker 添加到 _markers 集合中。新的部分是 Marker 的 position: _cameraCenter 赋值。 _cameraCenter 值是状态中的一个属性,用于跟踪 GoogleMap 小部件中相机的中心位置。它通过小部件的 onCameraMove 回调获取,如下所示:
GoogleMap(
...
onCameraMove: _cameraMove,
);
_cameraMove 方法只是简单地存储该值:
void _cameraMove(CameraPosition position) {
_cameraCenter = position.target;
}
这样,每次用户按下按钮时,都会在地图的相机中心目标位置添加一个标记。虽然这不是一个实际的用例,但这是与地图交互的一个实用起点。
2.2 GoogleMapController
GoogleMapController 类提供了另一种交互方式,它的工作方式与常见的控制器(如 TextEditingController )非常相似。 GoogleMapController 类旨在公开 GoogleMap 小部件的控制方法。目前,可用的方法如下:
- animateCamera :开始地图相机位置的动画更改。
- moveCamera :更改地图相机位置而不进行动画处理。
获取 GoogleMapController 的方式与其他可控制小部件不同,我们不需要自己向 GoogleMap 小部件提供控制器,而是通过之前看到的 onMapCreated 回调来获取。以下是存储控制器的代码:
GoogleMap(
...
onMapCreated: (controller) {
_mapController = controller;
},
);
_mapController 是 MapPage 小部件中的一个实例字段,用于与地图相机进行交互。
2.3 动画移动地图相机到指定位置
我们添加了一排按钮,用户可以按下这些按钮来聚焦到特定位置。例如,点击“Stonehenge”按钮会调用 _animateMapCameraTo 方法:
RaisedButton(
child: Text("Stonehenge"),
onPressed: () {
_animateMapCameraTo(_stonehengePosition);
},
);
_animateMapCameraTo 方法负责请求相机更新:
void _animateMapCameraTo(LatLng position) {
_mapController.animateCamera(CameraUpdate.newLatLng(position));
}
通过之前获取的 GoogleMapController 实例,我们可以将地图相机动画移动到新的位置。其他按钮的代码非常相似。
3. 使用Google Places API
Google Places API是一个通过HTTP请求返回地点信息的服务。地点在该API中定义为场所、地理位置或著名的兴趣点。该服务可以通过多种方式获取地点信息:
- 根据用户位置或搜索字符串获取地点列表。
- 获取特定地点的详细信息,包括用户评论。
- 访问Google地点数据库中存储的数百万张与地点相关的照片。
- 提供基于文本的地理搜索的查询预测服务,在用户输入时返回建议查询,并自动填充地点的名称和/或地址。
3.1 启用Google Places API
与Google Maps SDK一样,需要在Google开发者控制台( https://console.developers.google.com/apis/library/places-backend.googleapis.com )上启用Places API。确保处于正确的项目中,然后点击“ENABLE”按钮,这样就可以使用之前的API密钥来使用Places API。
3.2 使用google_maps_webservice插件
google_maps_webservice 插件是一个Dart社区插件,它提供了Google Places API的客户端。使用这个插件,我们可以直接调用Google Web服务,而无需自己创建请求。该插件将调用公开为其 GoogleMapsPlaces 类的方法,例如 getDetailsByPlaceId 方法,它调用Web服务的详细信息端点,并将响应包装在 PlacesDetailsResponse 类中。更多关于Web服务可用方法的信息,请查看插件页面: https://pub.dartlang.org/packages/google_maps_webservice 。
3.3 使用google_maps_webservice插件获取地点地址
- 首先,在项目的
pubspec.yaml文件中添加插件依赖,并使用flutter packages get命令获取它:
dependencies:
google_maps_webservice: ^0.0.12
- 然后,创建一个
GoogleMapsPlaces类的实例,以便访问提供的方法:
@override
void initState() {
super.initState();
_googleMapsPlaces = GoogleMapsPlaces(
apiKey: 'API_KEY',
);
}
这里在 initState 方法中创建实例,以便在地图显示给用户后立即使用。 _googleMapsPlaces 是 MapPage 小部件状态中的一个字段。
3. 定义一个方法,根据经纬度对查询地点名称:
Future<PlacesSearchResponse> _queryLatLngNearbyPlaces(LatLng position) async {
return await _googleMapsPlaces.searchNearbyWithRadius(
Location(position.latitude, position.longitude),
1000,
);
}
该方法使用 GoogleMapsPlaces 类的 searchNearbyWithRadius 方法,在Google Web服务上查询特定位置附近的地点,按其突出程度/重要性排序,最近的地点排在前面。
4. 修改 _addMarkerOnCameraCenter 函数,在添加标记到地图之前查询地点的地址:
void _addMarkerOnCameraCenter() async {
final places = await _queryLatLngNearbyPlaces(_cameraCenter);
final firstMatchName =
places.results.length > 0 ? places.results.first.name : "";
setState(() {
_markers.add(Marker(
markerId: MarkerId("${_markers.length + 1}"),
infoWindow: InfoWindow(
title: "Added marker - $firstMatchName"
),
icon: BitmapDescriptor.defaultMarker,
position: _cameraCenter,
));
});
}
与之前的版本相比,有以下修改:
- 方法现在是异步的,因为插件返回一个 Future 结果,我们需要等待它。
- 获取查询的第一个匹配项(仅其地址,如果有的话)。
- 在 InfoWindow 的 title 属性中添加名称信息。
添加到地图的标记现在包含了位置的名称。
4. 测试、调试和部署
Flutter提供了强大的工具来帮助开发者在平台上实现目标,从测试API到IDE工具和插件。在这部分,我们将学习如何添加测试以创建无错误的应用程序,调试以查找和解决特定问题,分析应用程序性能以找到瓶颈,以及检查UI小部件。还将学习如何为应用程序在App Store和Google Play上的部署做准备。
4.1 Flutter单元测试和小部件测试
手动测试移动应用程序是至关重要的,因为我们需要不断为应用程序添加功能。Flutter应用程序有多种测试方式,每种方式都有一定的好处,并且与测试其他软件应用程序没有太大区别。Flutter支持常见的单元测试和集成测试,此外,还可以编写小部件测试来单独测试小部件。
4.2 小部件测试
小部件测试用于以隔离的方式验证小部件。它们看起来与单元测试非常相似,但专注于小部件。主要目标是检查小部件的交互以及小部件是否按预期显示。由于小部件存在于Flutter上下文中的小部件树中,小部件测试需要在框架环境中执行。因此,Flutter通过 flutter_test 包提供了编写小部件测试的工具。
4.3 flutter_test包
flutter_test 包随Flutter SDK一起提供,它基于 test 包构建,并提供了一组工具来帮助我们编写和运行小部件测试。小部件测试需要在小部件环境中执行,Flutter通过 WidgetTester 类来帮助完成这项任务。该类封装了构建和与被测试小部件以及Flutter环境进行交互的逻辑。我们不需要自己实例化这个类,因为框架提供了 testWidgets() 函数。 testWidgets() 函数类似于之前在Dart单元测试中看到的 test() 函数,不同之处在于它设置了一个 WidgetTester 实例来与环境进行交互。
4.4 testWidgets函数
testWidgets 函数是Flutter中任何小部件测试的入口点:
void testWidgets(String description, WidgetTesterCallback callback, {
bool skip: false, Timeout timeout })
其参数说明如下:
- description :有助于记录测试,描述正在测试的小部件功能。
- callback :这是 WidgetTesterCallback ,该回调接收一个 WidgetTester 实例,以便我们可以与小部件进行交互并进行验证。这是测试的主体,我们在这里编写测试逻辑。
- skip :可以通过设置此标志在运行多个测试时跳过该测试。
- timeout :这是测试回调可以运行的最长时间。
4.5 小部件测试示例
生成Flutter项目时,会自动为我们添加 flutter_test 包依赖,并在 test/ 目录中生成一个示例测试。
1. 在 pubspec.yaml 文件中,添加了 flutter_test 包依赖:
dev_dependencies:
flutter_test:
sdk: flutter
注意,未指定包版本,并且源配置为Flutter SDK。
2. 在 test/widget_test.dart 文件中可以查看基本的小部件测试:
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
await tester.pumpWidget(MyApp());
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}
这个示例小部件测试验证了著名的Flutter计数器应用程序的行为。测试步骤如下:
1. 测试通过描述和 WidgetTesterCallback 属性定义。注意回调有 async 修饰符,因为 WidgetTester 方法返回 Future 类型。
2. 从 await tester.pumpWidget(MyApp()) 开始,这将渲染给定小部件(这里是 MyApp )的UI。
3. 如果需要在某个时刻重建小部件,可以使用 tester.pump() 方法。
4. 在小部件测试中, find 和 expect() 非常重要且常见:
- Finder 类允许我们在树中搜索特定的小部件。 find 常量提供了工具( Finders )来搜索和查找小部件树中的特定小部件。所有可用的 Finders 请查看: https://api.flutter.dev/flutter/flutter_driver/CommonFinders-class.html 。
- expect() 方法与 Matchers 结合使用,对通过 Finders 找到的小部件进行断言。 Matcher 有助于验证找到的小部件特征与预期值是否匹配。
分析上述小部件测试的断言:
1. 开始时,断言存在一个文本为 0 的小部件,不存在文本为 1 的小部件:
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
- 然后执行
tap()操作,随后请求pump()。点击包含Icons.add图标的小部件:
await tester.tap(find.byIcon(Icons.add));
await tester.pump()
- 最后一步是再次验证正确的文本是否显示。这次使用
findsOneWidget常量验证只有文本1可见:
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
与 find 常量一样,有多个 Matchers 可用; findsNothing 和 findsOneWidget 只是其中的一部分。所有可用的 Matchers 请查看 flutter_test 库文档: https://api.flutter.dev/flutter/flutter_test/flutter_test-library.html 。
4.6 调试Flutter应用程序
调试是软件开发中重要的一环。通过调试,我们可以解决小错误、奇怪的行为和复杂的bug。借助调试,我们可以进行以下操作:
- 进行逻辑断言。
- 确定需要改进的地方。
- 查找内存泄漏。
- 进行流程分析。
Flutter提供了多种工具来帮助完成这项任务。虽然我们没有评估特定的Flutter开发IDE,但Dart工具也为此做好了准备。
综上所述,我们学习了在Flutter中使用地图的基础知识,包括如何添加标记、与地图进行交互以及使用Google Places API获取位置信息。还了解了Flutter的测试、调试和部署相关内容,这些知识将帮助我们开发出更稳定、更高效的应用程序。
5. 性能分析与UI小部件检查
在开发Flutter应用时,性能分析和UI小部件检查是确保应用高质量的重要环节。
5.1 性能分析
性能分析是找出应用程序性能瓶颈的关键步骤。Flutter提供了一些工具来帮助开发者进行性能分析,例如:
- Flutter DevTools :这是一个强大的性能分析工具,它可以帮助开发者分析应用的CPU、内存使用情况,以及渲染性能等。通过它,开发者可以直观地看到应用在运行过程中的性能指标,从而找出可能存在的性能问题。
- Dart DevTools :Dart语言层面的性能分析工具,它可以深入到Dart代码的执行细节,帮助开发者分析代码的执行时间、内存分配等情况。
进行性能分析的一般步骤如下:
1. 打开Flutter DevTools或Dart DevTools。
2. 运行需要分析的Flutter应用。
3. 在DevTools中选择相应的分析功能,如CPU分析、内存分析等。
4. 操作应用,触发需要分析的功能或场景。
5. 观察DevTools中的分析结果,找出性能瓶颈。
5.2 UI小部件检查
UI小部件检查可以帮助开发者查看应用的UI结构,检查小部件的属性和状态。Flutter提供了一些工具来进行UI小部件检查,例如:
- Flutter Inspector :这是一个非常实用的工具,它可以让开发者直观地看到应用的UI结构,查看小部件的属性和状态。开发者可以通过它来调试UI布局问题,检查小部件的嵌套关系等。
- Widget Selector :用于在应用运行时选择特定的小部件进行检查。
使用Flutter Inspector进行UI小部件检查的步骤如下:
1. 运行Flutter应用。
2. 打开Flutter Inspector(可以在VS Code或Android Studio的调试工具中找到)。
3. 在Inspector中选择需要检查的小部件。
4. 查看小部件的属性和状态,进行调试和分析。
6. 为应用部署做准备
在完成应用的开发、测试和调试后,就需要为应用在App Store和Google Play上的部署做准备了。
6.1 准备应用图标和启动画面
应用图标和启动画面是用户对应用的第一印象,因此需要精心设计。
- 应用图标 :需要准备不同尺寸的图标,以适应不同设备的需求。一般来说,需要准备16x16、32x32、48x48、128x128等不同尺寸的图标。
- 启动画面 :启动画面可以在应用启动时显示,给用户更好的体验。可以使用Flutter的 flutter_native_splash 插件来快速生成启动画面。
准备应用图标和启动画面的步骤如下:
1. 设计应用图标和启动画面。
2. 将图标和启动画面添加到项目中。
3. 配置项目的 pubspec.yaml 文件,指定图标和启动画面的路径。
6.2 配置应用信息
在部署应用之前,需要配置应用的信息,例如应用名称、描述、版本号等。
- 应用名称 :应用在App Store和Google Play上显示的名称,需要简洁明了,具有吸引力。
- 应用描述 :详细描述应用的功能和特点,帮助用户了解应用。
- 版本号 :每次发布应用时,需要更新版本号,方便用户了解应用的更新情况。
配置应用信息的步骤如下:
1. 打开项目的 pubspec.yaml 文件。
2. 配置 name 、 description 、 version 等字段。
6.3 生成应用签名
在发布应用到App Store和Google Play之前,需要对应用进行签名。
- iOS应用签名 :需要使用Apple的开发者账号生成签名证书和描述文件。
- Android应用签名 :需要生成一个密钥库文件,并使用该密钥库对应用进行签名。
生成应用签名的步骤如下:
1. 对于iOS应用:
- 登录Apple开发者账号。
- 生成签名证书和描述文件。
- 将签名证书和描述文件添加到项目中。
2. 对于Android应用:
- 使用 keytool 命令生成密钥库文件。
- 使用 jarsigner 命令对应用进行签名。
6.4 提交应用到应用商店
完成上述准备工作后,就可以将应用提交到App Store和Google Play了。
- App Store :登录App Store Connect,创建新的应用记录,上传应用二进制文件,填写应用信息,然后提交审核。
- Google Play :登录Google Play Console,创建新的应用,上传应用APK文件,填写应用信息,然后提交审核。
提交应用到应用商店的步骤如下:
1. 登录相应的应用商店开发者平台。
2. 创建新的应用记录。
3. 上传应用二进制文件或APK文件。
4. 填写应用信息,包括应用名称、描述、图标、截图等。
5. 提交审核,等待审核结果。
7. 总结
通过以上内容的学习,我们全面了解了在Flutter中使用地图的相关知识,包括向地图添加标记、与地图进行交互、使用Google Places API获取位置信息等。同时,我们也掌握了Flutter应用的测试、调试、性能分析、UI小部件检查以及部署等方面的技能。
下面是一个简单的总结表格:
| 内容 | 要点 |
| ---- | ---- |
| 地图集成 | 使用 Marker 类添加标记,通过 GoogleMapController 与地图相机交互,利用Google Places API获取位置信息 |
| 测试 | 支持单元测试、集成测试和小部件测试,使用 flutter_test 包进行小部件测试 |
| 调试 | Flutter提供多种工具进行调试,可进行逻辑断言、查找内存泄漏等 |
| 性能分析 | 使用Flutter DevTools和Dart DevTools进行性能分析,找出性能瓶颈 |
| UI小部件检查 | 使用Flutter Inspector和Widget Selector进行UI小部件检查,调试UI布局问题 |
| 部署 | 准备应用图标和启动画面,配置应用信息,生成应用签名,提交应用到应用商店 |
整个开发和部署流程可以用以下mermaid流程图表示:
graph LR
A[开始开发] --> B[地图集成]
B --> C[测试]
C --> D[调试]
D --> E[性能分析]
E --> F[UI小部件检查]
F --> G[准备部署]
G --> H[提交应用到应用商店]
H --> I[完成部署]
这些知识和技能将帮助我们开发出功能丰富、性能优良、用户体验良好的Flutter应用。在未来的开发过程中,我们可以不断运用这些知识,持续优化应用,为用户带来更好的体验。
超级会员免费看
861

被折叠的 条评论
为什么被折叠?



