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'),  // 标记图片
                      ),
                    ),
                  ),
                ),
              ),
          ],
        );
      },
    );
  }
}

代码说明

  1. 初始化位置服务

    • initLocation() 方法用于检查并请求位置服务权限,并获取设备的当前位置。
    • location.onLocationChanged.listen() 用于监听位置变化,并将新的位置数据发送到 BehaviorSubject 流中。
  2. 位置数据处理

    • StreamBuilder 中,我们监听 locationSC 流中的位置数据。
    • 每次接收到新的位置数据时,计算与上次位置的时间差和距离,并使用 geodesy 库计算下一个模拟位置。
    • 更新地图的中心点为当前设备的位置。
  3. 动画标记

    • AnimatedMarkerLayer 用于在地图上显示带有动画效果的标记。
    • marker 参数定义了标记的外观,包括大小、位置和旋转角度。
    • duration 参数控制动画的持续时间,单位为毫秒。
  4. 地图层

    • TileLayer 用于加载地图瓦片,这里使用的是 OpenStreetMap 的默认瓦片服务。
    • AnimatedMarkerLayer 用于显示带有动画效果的标记,只有在有位置数据时才会显示。

注意事项

  • 请确保在 pubspec.yaml 中正确配置了 flutter_mapflutter_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

1 回复

更多关于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_mapflutter_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(),
                ),
              ),
            ),
          ],
        ),
      ],
    );
  }
}

代码解释:

  1. 依赖项

    • flutter_map:用于在 Flutter 中显示地图。
    • latlong2flutter_map 的依赖,用于处理地理坐标。
    • flutter_map_animated_marker:用于在地图上创建动画标记。
  2. 动画控制

    • 使用 AnimationControllerTween 来创建和控制动画。
    • 动画在 5 秒内从 01 重复,并且会反转。
  3. 地图设置

    • FlutterMap 组件用于显示地图。
    • TileLayerOptions 设置了地图的图层 URL 模板。
    • AnimatedMarkerLayerOptions 包含了动画标记的配置。
    • AnimatedMarker 使用 LatLngTween 在两个地理坐标之间进行动画。
  4. 标记

    • Marker 用于显示标记,这里使用 FlutterLogo 作为标记内容。

运行这个示例代码,你会看到一个带有动画标记的地图,标记会在两个地理位置之间来回移动。你可以根据需要调整动画参数和标记样式。

回到顶部