Flutter: How to move marker on map more smooth using Flutter_map package
Asked Answered
P

3

6

I'm a beginner in Flutter and I'm currently building a map app that display a map with current user's continuous location using Flutter_map plugin and I used marker to display it ..

It really working fine with me and the camera move well according to user's location but, the thing is that the marker actually jump from current position to new position, and I'd like to make the marker move in smoother way from a given latlon location to another one like we see in google maps user location marker. Is it possible to update it on the map by animation ? if yes could anyone show me how ?

(I don't want google maps marker solution cuz I prefer working with Flutter_map and displaying a leaflet map)

Here is my piece of code:

import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_map/plugin_api.dart';
import 'package:geolocator/geolocator.dart';
import 'package:latlong2/latlong.dart' as latLng;
import 'package:car_speed_limit/Components/constants.dart';
import 'dart:async';

//ignore: must_be_immutable
class RoadMap extends StatefulWidget {

  var userLat;
  var userLong;
  var userSpeed;

  RoadMap({this.userLat, this.userLong, this.userSpeed});

  @override
  _RoadMapState createState() => _RoadMapState();
}

class _RoadMapState extends State<RoadMap> with SingleTickerProviderStateMixin{

  MapController? _mapController;
  StreamSubscription<Position>? positionStreamSub2;

  @override
  void initState() {
    super.initState();
    _mapController = MapController(); 
    positionStreamSub2= Geolocator.getPositionStream(
        intervalDuration: Duration(milliseconds: 1000),
        forceAndroidLocationManager: false,
        desiredAccuracy: LocationAccuracy.best).listen((_updatedPosition) {
      if (!mounted) {
        return;
      }
      setState(() {
        _mapController?.move(latLng.LatLng(widget.userLat, widget.userLong),16.8);
        widget.userLat= _updatedPosition.latitude; 
        widget.userLong= _updatedPosition.longitude;
        widget.userSpeed= (_updatedPosition.speed*(2.23693)).toInt(); 
      });
      print('THE ROAD STREAM $_updatedPosition');
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('${widget.userSpeed}'),
          backgroundColor: Color(0xFF01051C),
          leading: IconButton(
              icon: Icon(
                Icons.arrow_back,
                color: kIconColor,
                size: 35,
              ),
              onPressed: () {
                Navigator.of(context).pop();
                positionStreamSub2?.cancel();
              }
          ),
          actions: [
            Column(
              children: [
                Text('Lat: ${widget.userLat}',
                    style: TextStyle(
                      color: kIconColor,
                    )),
                Text('Long: ${widget.userLong}',
                    style: TextStyle(
                      color: kIconColor,
                    )),
              ],
            ),
          ],
        ),
        body: FlutterMap(
            mapController: _mapController,
            options: MapOptions(
              minZoom: 2.6,
              maxZoom: 18.0,
              zoom: 17.0,
              center: latLng.LatLng(widget.userLat,widget.userLong),
              interactiveFlags: InteractiveFlag.pinchZoom | InteractiveFlag.drag | InteractiveFlag.pinchMove,
            ),
            layers: [
              TileLayerOptions(
                urlTemplate: 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', 
                subdomains: ['a','b','c'],
              ),
              MarkerLayerOptions(
                markers: [
                  Marker(
                      point: latLng.LatLng(widget.userLat,widget.userLong),
                      builder: (context) {
                        return Stack(
                          children:[
                            Center(
                              child: Container(
                                height: 30,
                                width: 30,
                                decoration: BoxDecoration(
                                  shape: BoxShape.circle,
                                  color: Colors.tealAccent.withOpacity(0.5),
                                ),
                              ),
                            ),
                            Center(
                              child: Container(
                                height: 17,
                                width: 17,
                                decoration: BoxDecoration(
                                  shape: BoxShape.circle,
                                  color: Colors.tealAccent[700],
                                ),
                              ),
                            ),
                          ],
                        );
                      }
                  ),
                ],
              ),
            ]
        ),
    );
  }
}
Posh answered 3/11, 2021 at 18:9 Comment(2)
unfortunately not yet but, someone told me that you could just reduce the intervalDuration property in the getPoistionStream to 10 milliseconds, it went more smooth but still not as smooth as Google mapsPosh
google_maps_flutter: ^2.1.3 this one is official, did you try using this??Sticktight
B
4

I was looking for a way to add a nice animation when moving the map controller, and found that it's quite easy - you just call 'move' using an animation controller. There is an example of how to do this in the flutter_map repo:

animated_map_controller.dart

The general idea is not to use the mapcontroller directly, but control it with an animation controller that 'tweens' the zoom and position:

void _animatedMapMove(LatLng destLocation, double destZoom) {
    // Create some tweens. These serve to split up the transition from one location to another.
    // In our case, we want to split the transition be<tween> our current map center and the destination.
    final latTween = Tween<double>(
        begin: mapController.center.latitude, end: destLocation.latitude);
    final lngTween = Tween<double>(
        begin: mapController.center.longitude, end: destLocation.longitude);
    final zoomTween = Tween<double>(begin: mapController.zoom, end: destZoom);

    // Create a animation controller that has a duration and a TickerProvider.
    final controller = AnimationController(
        duration: const Duration(milliseconds: 500), vsync: this);
    // The animation determines what path the animation will take. You can try different Curves values, although I found
    // fastOutSlowIn to be my favorite.
    final Animation<double> animation =
        CurvedAnimation(parent: controller, curve: Curves.fastOutSlowIn);

    controller.addListener(() {
      mapController.move(
          LatLng(latTween.evaluate(animation), lngTween.evaluate(animation)),
          zoomTween.evaluate(animation));
    });

    animation.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        controller.dispose();
      } else if (status == AnimationStatus.dismissed) {
        controller.dispose();
      }
    });

    controller.forward();
  }

This is not my code, but I used something similar in my project. Remember that your widget has to use the TickerProviderStateMixin. Hope this helps someone!

Burny answered 2/8, 2022 at 15:33 Comment(1)
THIS ONLY MOVES THE CAMERA NOT THE MARKERCornie
S
0

If you're using multiple mixins you would want to use
TickerProviderStateMixin
instead of the SingleTickerProviderStateMixin.

Seidler answered 19/11, 2022 at 17:6 Comment(0)
O
0

You can use flutter_map_animations package which adds a wrapper for MapController that handles animating the camera position, rotation, zoom, and even has some marker animation features:

class _State extends State<YourWidget> with TickerProviderStateMixin {
  late final _animatedMapController = AnimatedMapController(vsync: this);

  void dispose() {
    _animatedMapController.dispose();
    super.dispose();
  }
}

Pass the _animatedMapController.mapController to your FlutterMap.mapController. You can now take advantage of its animated methods.

Overpowering answered 27/5, 2024 at 12:7 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.