Flutter动画标记插件flutter_map_animated_marker的使用
Flutter动画标记插件flutter_map_animated_marker的使用
flutter_map_animated_marker
是一个用于在 flutter_map
中添加动画标记的插件。通过这个插件,你可以在地图上创建动态移动的标记,例如模拟车辆或人员的移动路径。下面是一个完整的示例 Demo,展示了如何使用 flutter_map_animated_marker
插件。
功能特性
- 动画标记:可以在地图上创建带有动画效果的标记,标记会根据指定的路径或位置变化进行移动。
入门指南
首先,在 pubspec.yaml
文件中添加 flutter_map_animated_marker
依赖:
dependencies:
flutter_map_animated_marker:
然后运行 flutter pub get
来安装依赖。
使用示例
以下是一个完整的示例代码,展示了如何使用 flutter_map_animated_marker
插件来创建一个带有动画效果的标记,并根据设备的位置数据进行更新。
import 'dart:async';
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_map_animated_marker/flutter_map_animated_marker.dart';
import 'package:latlong2/latlong.dart';
import 'package:location/location.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Map Animated Marker Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MapScreen(),
);
}
}
class MapScreen extends StatefulWidget {
const MapScreen({Key? key}) : super(key: key);
@override
_MapScreenState createState() => _MapScreenState();
}
class _MapScreenState extends State<MapScreen> with TickerProviderStateMixin {
final Location location = Location();
final geodesy.Geodesy _geodesy = geodesy.Geodesy();
final BehaviorSubject<LocationData> locationSC = BehaviorSubject();
final mapController = MapController();
LocationData? lastFix;
int duration = 0;
double distance = 0;
Future<void> initLocation() async {
bool _serviceEnabled;
PermissionStatus _permissionGranted;
// 检查并请求位置服务权限
_serviceEnabled = await location.serviceEnabled();
if (!_serviceEnabled) {
_serviceEnabled = await location.requestService();
if (!_serviceEnabled) {
return;
}
}
_permissionGranted = await location.hasPermission();
if (_permissionGranted == PermissionStatus.denied) {
_permissionGranted = await location.requestPermission();
if (_permissionGranted != PermissionStatus.granted) {
return;
}
}
// 获取初始位置数据
location.getLocation().then((value) {
locationSC.add(value);
});
// 监听位置变化
location.onLocationChanged.listen((event) {
locationSC.add(event);
});
}
@override
void initState() {
super.initState();
initLocation();
// 监听位置数据流
locationSC.stream.listen((event) {
// 计算时间差和距离
duration = ((event.time ?? 0) - (lastFix?.time ?? 0)).toInt();
distance = _geodesy.distanceBetweenTwoGeoPoints(
geodesy.LatLng(event.latitude ?? 0, event.longitude ?? 0),
geodesy.LatLng(lastFix?.latitude ?? 0, lastFix?.longitude ?? 0),
).toDouble();
// 更新最后的位置数据
lastFix = event;
// 移动地图到当前位置
mapController.move(
LatLng(lastFix?.latitude ?? 0, lastFix?.longitude ?? 0),
16,
);
});
}
@override
void dispose() {
locationSC.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return StreamBuilder<LocationData>(
stream: locationSC.stream,
builder: (context, snapshot) {
final locationData = snapshot.data;
// 如果有位置数据,计算下一个模拟位置
final nextSimulateLocation = locationData != null
? _geodesy.destinationPointByDistanceAndBearing(
geodesy.LatLng(locationData.latitude ?? 0.0, locationData.longitude ?? 0.0),
distance,
locationData.heading ?? 0.0,
)
: null;
return FlutterMap(
mapController: mapController,
options: MapOptions(
center: LatLng(51.509364, -0.128928), // 初始中心点
zoom: 9.2, // 初始缩放级别
),
children: [
TileLayer(
urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', // 地图瓦片URL
),
if (locationData != null && nextSimulateLocation != null)
AnimatedMarkerLayer(
options: AnimatedMarkerLayerOptions(
duration: Duration(milliseconds: duration), // 动画持续时间
marker: Marker(
width: 30, // 标记宽度
height: 30, // 标记高度
alignment: Alignment.center, // 标记对齐方式
point: LatLng(
nextSimulateLocation.latitude, // 标记位置
nextSimulateLocation.longitude,
),
child: Center(
child: Transform.rotate(
angle: max(0, locationData.heading ?? 0) * math.pi / 180, // 根据方向旋转标记
child: Image.asset('lib/assets/puck.png'), // 标记图片
),
),
),
),
),
],
);
},
);
}
}
代码说明
-
初始化位置服务:
initLocation()
方法用于检查并请求位置服务权限,并获取设备的当前位置。location.onLocationChanged.listen()
用于监听位置变化,并将新的位置数据发送到BehaviorSubject
流中。
-
位置数据处理:
- 在
StreamBuilder
中,我们监听locationSC
流中的位置数据。 - 每次接收到新的位置数据时,计算与上次位置的时间差和距离,并使用
geodesy
库计算下一个模拟位置。 - 更新地图的中心点为当前设备的位置。
- 在
-
动画标记:
AnimatedMarkerLayer
用于在地图上显示带有动画效果的标记。marker
参数定义了标记的外观,包括大小、位置和旋转角度。duration
参数控制动画的持续时间,单位为毫秒。
-
地图层:
TileLayer
用于加载地图瓦片,这里使用的是 OpenStreetMap 的默认瓦片服务。AnimatedMarkerLayer
用于显示带有动画效果的标记,只有在有位置数据时才会显示。
注意事项
- 请确保在
pubspec.yaml
中正确配置了flutter_map
和flutter_map_animated_marker
依赖。 - 你需要在项目中添加一个名为
puck.png
的图片资源,作为标记的图标。你可以将其放在lib/assets/
目录下,并在pubspec.yaml
中添加资源路径。
flutter:
assets:
- lib/assets/puck.png
更多关于Flutter动画标记插件flutter_map_animated_marker的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter动画标记插件flutter_map_animated_marker的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何使用 flutter_map_animated_marker
插件的示例代码。这个插件允许你在 Flutter 的 flutter_map
上创建动画标记。
首先,确保你已经在 pubspec.yaml
文件中添加了必要的依赖:
dependencies:
flutter:
sdk: flutter
flutter_map: ^0.14.0 # 请检查最新版本
latlong2: ^0.8.0 # flutter_map 的依赖
flutter_map_animated_marker: ^0.3.0 # 请检查最新版本
然后,运行 flutter pub get
来安装这些依赖。
接下来,创建一个 Flutter 应用,并在其中使用 flutter_map
和 flutter_map_animated_marker
。以下是一个完整的示例代码:
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
import 'package:flutter_map_animated_marker/flutter_map_animated_marker.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter Map Animated Marker Example'),
),
body: MapScreen(),
),
);
}
}
class MapScreen extends StatefulWidget {
@override
_MapScreenState createState() => _MapScreenState();
}
class _MapScreenState extends State<MapScreen> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 5),
vsync: this,
)..repeat(reverse: true);
_animation = Tween<double>(begin: 0, end: 1).animate(CurvedAnimation(
parent: _controller,
curve: Curves.linear,
));
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return FlutterMap(
options: MapOptions(
center: LatLng(51.5, -0.09),
zoom: 13,
),
layers: [
TileLayerOptions(
urlTemplate: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
subdomains: ['a', 'b', 'c'],
),
AnimatedMarkerLayerOptions(
markers: [
AnimatedMarker(
latLng: LatLngTween(
begin: LatLng(51.5, -0.1),
end: LatLng(51.51, -0.08),
).animate(_animation),
child: Marker(
width: 80.0,
height: 80.0,
pointAnchor: Alignment.center,
anchorPos: AnchorPos.center,
builder: (ctx) => Container(
child: FlutterLogo(),
),
),
),
],
),
],
);
}
}
代码解释:
-
依赖项:
flutter_map
:用于在 Flutter 中显示地图。latlong2
:flutter_map
的依赖,用于处理地理坐标。flutter_map_animated_marker
:用于在地图上创建动画标记。
-
动画控制:
- 使用
AnimationController
和Tween
来创建和控制动画。 - 动画在 5 秒内从
0
到1
重复,并且会反转。
- 使用
-
地图设置:
FlutterMap
组件用于显示地图。TileLayerOptions
设置了地图的图层 URL 模板。AnimatedMarkerLayerOptions
包含了动画标记的配置。AnimatedMarker
使用LatLngTween
在两个地理坐标之间进行动画。
-
标记:
Marker
用于显示标记,这里使用FlutterLogo
作为标记内容。
运行这个示例代码,你会看到一个带有动画标记的地图,标记会在两个地理位置之间来回移动。你可以根据需要调整动画参数和标记样式。