Flutter动画标记沿路线插件animated_marker_along_route的使用

发布于 1周前 作者 yuanlaile 来自 Flutter

Flutter动画标记沿路线插件animated_marker_along_route的使用

简介

本插件支持平滑地在地图上移动动画标记。

完整示例Demo

import 'dart:developer';

import 'package:flutter/material.dart';
import 'package:vietmap_flutter_gl/vietmap_flutter_gl.dart';
import 'package:vietmap_flutter_plugin/vietmap_flutter_plugin.dart';
import 'package:vietmap_gl_platform_interface/vietmap_gl_platform_interface.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const DriverTracking(),
    );
  }
}

class DriverTracking extends StatefulWidget {
  const DriverTracking({super.key});

  [@override](/user/override)
  State<DriverTracking> createState() => _DriverTrackingState();
}

class _DriverTrackingState extends State<DriverTracking> with TickerProviderStateMixin {
  VietmapController? vietmapController;
  VietMapRoutingModel? route;
  Line? _routeLine;
  Marker? _storeMarker;
  Marker? _customerMarker;
  LatLng? _driverLatLng = const LatLng(10.757549832396515, 106.65865699447431);
  double _driverBearing = 0;
  RouteSimulator? routeSimulator;

  [@override](/user/override)
  void initState() {
    Vietmap.getInstance('YOUR_API_KEY_HERE');
    super.initState();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          _simulateDriverLocation();
        },
        child: const Icon(Icons.start),
      ),
      body: Stack(
        children: [
          VietmapGL(
            trackCameraPosition: true,
            onMapCreated: (controller) {
              vietmapController = controller;
            },
            onMapRenderedCallback: () async {
              _drawStoreMarker();
              _drawUserMarker();
              await _fetchRoute();
            },
            initialCameraPosition: const CameraPosition(
                target: LatLng(10.757549832396515, 106.65865699447431),
                zoom: 10),
            styleString: Vietmap.getVietmapStyleUrl(),
          ),
          if (vietmapController != null && _driverLatLng != null)
            StaticMarkerLayer(
                markers: [_driverMarker], mapController: vietmapController!),
          if (vietmapController != null &&
              _storeMarker != null &&
              _customerMarker != null)
            MarkerLayer(
                markers: [_storeMarker!, _customerMarker!],
                mapController: vietmapController!),
        ],
      ),
    );
  }

  /// This function uses the RouteSimulator to simulate the driver's location,
  /// which is moving along the route. Please call the [_updateDriverLocation]
  /// function for production.
  _simulateDriverLocation() {
    vietmapController
        ?.moveCamera(CameraUpdate.newLatLngZoom(_driverLatLng!, 16));
    if (route?.paths?.isNotEmpty != true) throw 'Not found route';

    /// Create the simulator, modify the upperBound and duration to change the speed & time of the driver
    routeSimulator = RouteSimulator(
        route?.paths?.first.pointsLatLng ?? [], this,
        upperBound: 2.2, duration: const Duration(seconds: 19), repeat: false);
    routeSimulator!.addV2Listener((LatLng? latLng, int? index, double? distance,
            LatLng? previousLatLng) =>
        setState(() {
          if (latLng != null) {
            _driverLatLng = latLng;

            if (previousLatLng != null) {
              /// This code just for mock location,
              /// replace with your own driver bearing
              _driverBearing =
                  VietmapPolyline.calculateFinalBearing(previousLatLng, latLng);
            }

            /// NOTE: - Update the route line on the map here
            List<LatLng> remainingRoute = VietMapSnapEngine.getRouteRemaining(
                route?.paths?.first.pointsLatLng ?? [], latLng);
            _updateTheRouteOnMap(remainingRoute, latLng);
            _checkAndNotifyCustomer(
                route?.paths?.first.pointsLatLng ?? [], latLng);
            _checkIsDriverOffRoute(
                route?.paths?.first.pointsLatLng ?? [], latLng);
            vietmapController?.animateCamera(CameraUpdate.newLatLng(latLng),
                duration: const Duration(milliseconds: 100));
          }
        }));

    /// Start the simulator, will mock the driver's location moving along the route
    routeSimulator!.start();
  }

  // ignore: unused_element
  _updateDriverLocation(double bearing, LatLng driverLocation) {
    setState(() {
      _driverBearing = bearing;
      _driverLatLng = driverLocation;
    });

    List<LatLng> remainingRoute = VietMapSnapEngine.getRouteRemaining(
        route?.paths?.first.pointsLatLng ?? [], driverLocation);
    _updateTheRouteOnMap(remainingRoute, driverLocation);
    _checkAndNotifyCustomer(
        route?.paths?.first.pointsLatLng ?? [], driverLocation);
    _checkIsDriverOffRoute(
        route?.paths?.first.pointsLatLng ?? [], driverLocation);
  }

  _checkIsDriverOffRoute(List<LatLng> route, LatLng latLng) async {
    bool isDriverOffRoute = VietMapSnapEngine.isUserOffRoute(route, latLng);
    if (isDriverOffRoute) {
      /// NOTE: - Notify the driver that he is off route
      /// fetch the new route and update the route line on the map, then continue
      /// calculating the driver's location with the new route.
    }
  }

  _updateTheRouteOnMap(List<LatLng> route, LatLng latLng) {
    if (_routeLine != null) {
      vietmapController?.updatePolyline(
          _routeLine!,
          PolylineOptions(
              geometry: route, polylineColor: Colors.red, polylineWidth: 5));
    }
  }

  _checkAndNotifyCustomer(List<LatLng> route, LatLng latLng) {
    /// Check if the driver is near the customer and send notify.
    double distanceRemaining =
        VietMapSnapEngine.distanceToEndOfRoute(route, latLng);

    if (distanceRemaining < 200) {
      // NOTE: - Notify the customer here
      log(distanceRemaining.toString());
      log('Alert for the customer to prepare for the delivery');
      routeSimulator?.stop();
    }
  }

  _fetchRoute() async {
    var res = await Vietmap.routing(VietMapRoutingParams(points: [
      const LatLng(10.757549832396515, 106.65865699447431),
      const LatLng(10.759095569892626, 106.67595646986068)
    ]));
    res.fold((l) {
      throw l;
    }, (r) {
      setState(() {
        route = r;
      });
      _drawRoute();
      return r;
    });
  }

  _drawStoreMarker() {
    setState(() {
      _storeMarker = Marker(
        width: 50,
        height: 50,
        child: IgnorePointer(
            child: Image.asset(
          'assets/store_marker.png',
          width: 50,
          height: 50,
        )),
        alignment: Alignment.bottomCenter,
        latLng: const LatLng(10.757549832396515, 106.65865699447431),
      );
    });
  }

  _drawUserMarker() {
    setState(() {
      _customerMarker = Marker(
          width: 50,
          height: 50,
          child: IgnorePointer(
              child: Image.asset(
            'assets/user_marker.png',
            width: 50,
            height: 50,
          )),
          alignment: Alignment.bottomCenter,
          latLng: const LatLng(10.759095569892626, 106.67595646986068));
    });
  }

  _drawRoute() async {
    _routeLine = await vietmapController?.addPolyline(PolylineOptions(
        geometry: route?.paths?.first.pointsLatLng,
        polylineColor: Colors.red,
        polylineWidth: 5));
  }

  StaticMarker get _driverMarker => StaticMarker(
        width: 40,
        height: 50,
        bearing: _driverBearing,
        child: IgnorePointer(
            child: Image.asset(
          'assets/driver.png',
          width: 40,
          height: 50,
        )),
        alignment: Alignment.center,
        latLng: _driverLatLng!,
      );
}

更多关于Flutter动画标记沿路线插件animated_marker_along_route的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter动画标记沿路线插件animated_marker_along_route的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


animated_marker_along_route 是一个用于在 Flutter 应用中沿特定路线移动标记的插件。它通常用于地图应用中,比如 Google Maps 或 Mapbox,以展示一个标记沿预定路径移动的动画效果。

以下是如何使用 animated_marker_along_route 插件的基本步骤:

1. 添加依赖

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

dependencies:
  flutter:
    sdk: flutter
  animated_marker_along_route: ^1.0.0  # 请检查最新版本

然后运行 flutter pub get 以安装依赖。

2. 导入包

在你的 Dart 文件中导入 animated_marker_along_route 包:

import 'package:animated_marker_along_route/animated_marker_along_route.dart';

3. 创建路线

你需要定义一个路线,通常是一个包含多个经纬度坐标的列表。例如:

List<LatLng> route = [
  LatLng(37.7749, -122.4194), // 起点
  LatLng(34.0522, -118.2437), // 终点
  // 可以添加更多的中间点
];

4. 创建 AnimatedMarkerAlongRoute

接下来,你可以创建一个 AnimatedMarkerAlongRoute 对象,并将其添加到地图上。以下是一个基本的示例:

AnimatedMarkerAlongRoute(
  route: route, // 传递路线
  markerIcon: BitmapDescriptor.defaultMarker, // 标记图标
  duration: Duration(seconds: 10), // 动画持续时间
  onAnimationEnd: () {
    // 动画结束时的回调
    print("Animation ended");
  },
);

5. 在地图上显示

你需要将 AnimatedMarkerAlongRoute 添加到地图的 markers 集合中。以下是一个完整的示例,假设你正在使用 google_maps_flutter 插件:

import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:animated_marker_along_route/animated_marker_along_route.dart';

class MapScreen extends StatefulWidget {
  [@override](/user/override)
  _MapScreenState createState() => _MapScreenState();
}

class _MapScreenState extends State<MapScreen> {
  GoogleMapController? mapController;
  Set<Marker> markers = {};

  List<LatLng> route = [
    LatLng(37.7749, -122.4194), // 起点
    LatLng(34.0522, -118.2437), // 终点
  ];

  [@override](/user/override)
  void initState() {
    super.initState();
    markers.add(
      Marker(
        markerId: MarkerId('animated_marker'),
        position: route.first,
        icon: BitmapDescriptor.defaultMarker,
      ),
    );
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      body: GoogleMap(
        onMapCreated: (controller) {
          setState(() {
            mapController = controller;
          });
        },
        initialCameraPosition: CameraPosition(
          target: route.first,
          zoom: 10,
        ),
        markers: markers,
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            markers.add(
              AnimatedMarkerAlongRoute(
                route: route,
                markerIcon: BitmapDescriptor.defaultMarker,
                duration: Duration(seconds: 10),
                onAnimationEnd: () {
                  print("Animation ended");
                },
              ).toMarker(MarkerId('animated_marker')),
            );
          });
        },
        child: Icon(Icons.play_arrow),
      ),
    );
  }
}
回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!