1

I'm building an application with Flutter, based on a map. So I use the Google Maps package and all's working fine. But, I tried to add a FloatingActionButton to recenter the map on my location, and here, I got a problem. First, the map doesn't recenter on my location and second, I get an horrible red error. Here are the code, the flutter doctor, and the error code.

My code:

import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:provider/provider.dart';
import 'package:spotycar/providers/location_service.dart';

import '../../models/user_location.dart';

class MapWidget extends StatefulWidget {
  MapWidget({@required Key key}) : super(key: key);

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

var locationClicked = false;

class _MapWidgetState extends State<MapWidget> {
  @override
  Widget build(BuildContext context) {
    CameraUpdate cameraUpdate;
    GoogleMapController mapController;
    var location = Provider.of<UserLocation>(context);
    final provider = Provider.of<LocationService>(context);
    final double _zoom = 17.0;
    final double _tilt = 37.0;
    var _coord;

    if (provider.loadedLocation) {
      _coord = LatLng(location.latitude, location.longitude);
      cameraUpdate = CameraUpdate.newCameraPosition(CameraPosition(
        target: _coord,
        bearing: location.heading,
        zoom: _zoom,
        tilt: _tilt,
      ));
    }

    if (locationClicked == true) {
      mapController.moveCamera(
        CameraUpdate.newCameraPosition(
          CameraPosition(
            target: _coord,
            bearing: location.heading,
            zoom: _zoom,
            tilt: _tilt,
          ),
        ),
      );
      setState(() {
        locationClicked = false;
      });
    }

    return Scaffold(
      body: !provider.loadedLocation
          ? Center(
              child: CircularProgressIndicator(
                valueColor: AlwaysStoppedAnimation<Color>(Colors.purple),
              ),
            )
          : GoogleMap(
              onMapCreated: (GoogleMapController controller) {
                mapController = controller;
                mapController.animateCamera(cameraUpdate);
              },
              myLocationEnabled: true,
              myLocationButtonEnabled: false,
              zoomControlsEnabled: false,
              initialCameraPosition: CameraPosition(
                target: _coord,
                zoom: _zoom,
                tilt: _tilt,
              ),
              rotateGesturesEnabled: true,
            ),
    );
  }
}

class LocationRechercheWidget extends StatefulWidget {
  @override
  _LocationRechercheWidgetState createState() =>
      _LocationRechercheWidgetState();
}

class _LocationRechercheWidgetState extends State<LocationRechercheWidget> {
  @override
  Widget build(BuildContext context) {
    return FloatingActionButton(
      child: Icon(
        Icons.location_searching,
        color: Colors.purple,
        size: 25,
      ),
      backgroundColor: Colors.white,
      onPressed: () {
        setState(() {
          locationClicked = true;
        });
      },
    );
  }
}

My Flutter doctor :

[√] Flutter (Channel master, 1.20.0-3.0.pre.124, on Microsoft Windows [version 10.0.18362.900], locale fr-FR)
    • Flutter version 1.20.0-3.0.pre.124 at C:\flutter
    • Framework revision ec3368ae45 (2 days ago), 2020-07-02 01:58:01 -0400
    • Engine revision 65ac8be350
    • Dart version 2.9.0 (build 2.9.0-20.0.dev f8ff12008e)

 
[√] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
    • Android SDK at C:\Users\adrie\AppData\Local\Android\sdk
    • Platform android-29, build-tools 29.0.2
    • Java binary at: C:\Program Files\Android\Android Studio1310\jre\bin\java
    • Java version OpenJDK Runtime Environment (build 1.8.0_212-release-1586-b04)
    • All Android licenses accepted.

[√] Android Studio (version 3.6)
    • Android Studio at C:\Program Files\Android\Android Studio1310
    • Flutter plugin version 45.1.1
    • Dart plugin version 192.7761
    • Java version OpenJDK Runtime Environment (build 1.8.0_212-release-1586-b04)

[√] VS Code (version 1.46.1)
    • VS Code at C:\Users\adrie\AppData\Local\Programs\Microsoft VS Code
    • Flutter extension version 3.12.1

[√] Connected device (1 available)
    • Mi Note 10 (mobile) • 53bd04cc • android-arm64 • Android 10 (API 29)

• No issues found!

And The error that I'm getting when I click on the FloatingActionButton :

═╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following NoSuchMethodError was thrown building MapWidget-[#2721f](dirty, dependencies:
[InheritedProvider<UserLocation>, InheritedProvider<LocationService>], state:
_MapWidgetState#50617):
The method 'moveCamera' was called on null.
Receiver: null
Tried calling: moveCamera(Instance of 'CameraUpdate')
The relevant error-causing widget was:
  MapWidget-[#2721f]
  
lib\screen\map_screen.dart:20
When the exception was thrown, this was the stack:
#0      Object.noSuchMethod  (dart:core-patch/object_patch.dart:51:5)
#1      _MapWidgetState.build 
package:spotycar/…/map_screen/map_widget.dart:39
#2      StatefulElement.build 
package:flutter/…/widgets/framework.dart:4663
#3      ComponentElement.performRebuild 
package:flutter/…/widgets/framework.dart:4546
#4      StatefulElement.performRebuild 
package:flutter/…/widgets/framework.dart:4719
#5      Element.rebuild 
package:flutter/…/widgets/framework.dart:4262
#6      BuildOwner.buildScope 
package:flutter/…/widgets/framework.dart:2667
#7      WidgetsBinding.drawFrame 
package:flutter/…/widgets/binding.dart:866
#8      RendererBinding._handlePersistentFrameCallback 
package:flutter/…/rendering/binding.dart:286
#9      SchedulerBinding._invokeFrameCallback 
package:flutter/…/scheduler/binding.dart:1115
#10     SchedulerBinding.handleDrawFrame 
package:flutter/…/scheduler/binding.dart:1054
#11     SchedulerBinding._handleDrawFrame 
package:flutter/…/scheduler/binding.dart:970
#15     _invoke  (dart:ui/hooks.dart:253:10)
#16     _drawFrame  (dart:ui/hooks.dart:211:3)
(elided 3 frames from dart:async)
Vayhuit
  • 316
  • 5
  • 12
  • add some code for this method 'moveCamera' was called on null. – griffins Jul 04 '20 at 03:25
  • @griffins Excuse me but, I haven't understood your answer. The method 'moveCamera' isn't mine but it's a method from the package. I added a print of 'cameraUpdate' in the 'onMapCreated' method and it return 'Instance of 'CameraUpdate', but it actually works. And ten days later, I still have the same issue, so all your help is welcome ! :) – Vayhuit Jul 13 '20 at 22:42
  • what dependencies do you have? I'm trying to run your code to replicate the issue – jabamataro Jul 23 '20 at 12:58
  • Thanks but i got the solution on GitHub : https://github.com/flutter/flutter/issues/61451 – Vayhuit Jul 24 '20 at 15:56
  • 1
    You have mentioned in the comment that you've resolved the issue. Could you share some insights that would let the community see what the solution is? You can put it in the answer section and accept as answer. – MαπμQμαπkγVπ.0 May 12 '21 at 19:38
  • @MαπμQμαπkγVπ.0 I posted the answer, sorry for the wait. – Vayhuit May 15 '21 at 12:02

3 Answers3

18

To solve this issue, you need to use a Completer instead of a simple GoogleMapController.

When you instantiate it :

Completer<GoogleMapController> _controller = Completer();

Then in the onMapCreated method inside your GoogleMap widget :

onMapCreated: (GoogleMapController controller) {
      _controller.complete(controller);
      ...
},

And whenever you wanna change the camera position :

Future<void> moveCamera() async {
  final GoogleMapController controller = await _controller.future;
  controller.moveCamera(CameraUpdate.newCameraPosition(CameraPosition(
    target: LatLong(..., ...),
    zoom: ...,
  )));
}

And you should be good !

Vayhuit
  • 316
  • 5
  • 12
  • 1
    Completer is no longer required in current versions. You can use the controller directly. I'm using `google_maps_flutter: ^2.1.1`. – Ali Akber Dec 08 '21 at 09:11
0

I had this issue, I had the exact code that was being used by Vayhuit. My pin would update but the cam whent to the last place I had searched. to solve this I had to change

static final CameraPosition _location = CameraPosition(
target: LatLng(lat!, lng!),
zoom: 15,
);

I had an init state so I created a

late CameraPosition _location;

and then

 getLocation() {
_location = CameraPosition(
  target: LatLng(lat!, lng!),
  zoom: 15,
     );
   }

Then I just added getLocation(); to the initstate. seems to work now.

0

For those who are using FlutterMap or MapBox in Flutter

The above answers are right but I will add one thing, that was a big problem for me as well. How to keep the zoom level according to the user zoom because when you listen for the current location changes and update your camera position according to it then the zoom level is also picking the one that you provide at the start.


for example: you provide the zoom level 13 at the start and you zoom the screen to 16 then when the camera position updates it will bring you again to zoom level 13, and it is repeating after every second which is really annoying, So you have to provide the zoom level dynamically which will change according to the user zoom level.


First Listen to the location stream:

location.onLocationChanged.listen((event) {
final newLatLng = LatLng(event.latitude!, event.longitude!);
// Use mapController to access the move method
// move() method is used for the camera position changing e.g: move(LatLng center,   double zoom)
mapController.move(newLatLng , 13);  // this will set the zoom level static to 13
// but we want it to be dynamic according to the user zoom level,
// so then use the mapController.zoom property will dynamically adjust your zoom level
 mapController.move(newLatLng , mapController.zoom); 
});
Abdur Rehman
  • 313
  • 2
  • 6