Search code examples
fluttersetstate

Flutter buttons onpressed function continually being called when state created or state set


I am using the google maps plugin and have a button that adds a marker onto the map.

The problem is when the screen first loads the button function (_onAddMarkerButtonPressed) is called straight away and puts down a marker on the map. I am guessing this is from the createSate() method.

I also have a textview that is updated with the new location address on the map whenever the the map is moved (_onCameraMove). This is calling setState() after changing the value of the String that is shown in that Text widget. However, this is not just updating the text it is also calling the _onAddMarkerButtonPressed and adding a new marker every time the camera is moved on the map. So I am ending up with a screenful of markers.

Thanks for your help.

 class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

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

class _MyHomePageState extends State<MyHomePage> {

  Completer<GoogleMapController> _controller = Completer();
  static const LatLng _center  = const LatLng(-31.950260, 115.851840);
  final Set<Marker> _markers = {};
  LatLng _lastMapPosition = _center;

  @override
  Widget build(BuildContext context) {

    double mapWidth = MediaQuery.of(context).size.width;
    double mapHeight = MediaQuery.of(context).size.height - 215;
    double iconSize = 30.0;

    return Scaffold(
      appBar: AppBar(

        title: Text(widget.title),
      ),
      body: Stack(
        alignment: Alignment(0.0, 0.0),
        children: <Widget>[
          GoogleMap(
            onMapCreated: _onMapCreated,
            initialCameraPosition: CameraPosition(target: _center, zoom: 16.0),
            mapType: MapType.normal,
            markers: _markers,
            onCameraMove: _onCameraMove,
          ),

          Positioned(
            top: 0,
            child: Padding(
              padding: const EdgeInsets.all(16.0),
              child: Container(
                  decoration: BoxDecoration( borderRadius: BorderRadius.circular(10.0), color: Colors.white),
                  height: 75,
                  width: mapWidth,
                  child: Center(
                      child: Text(address))),
            ),
          ),

         Positioned(
          top: (mapHeight - iconSize)/ 2,
          right: (mapWidth - iconSize)/ 2,
          child: Icon(Icons.my_location, size: iconSize, color: Colors.black87,),
        ),

         Positioned(
           bottom: 24.0,
           left: 24.0,
           child: Icon(Icons.search, size: 40, color: Colors.blue,) ,
        ),

          Positioned(
            bottom: 24.0 - (42/2),
            right: (mapWidth - 150)/ 2,
            child: RoundedButton(title: 'Add Alert', color: Colors.lightBlueAccent, onPressed: _onAddMarkerButtonPressed()),
          ),

        Positioned(
          bottom: 24.00,
          right: 24.0,
          child: Icon(Icons.my_location, size: 40, color: Colors.blue,) ,
        ),
      ],
    ),
  );
}


  _onAddMarkerButtonPressed (){
    setState(() {
      _markers.add(Marker(
          markerId: MarkerId(_lastMapPosition.toString()),
          position: _lastMapPosition,
          infoWindow: InfoWindow(
            title: 'This is the title',
            snippet: 'This is the snippet',
          ),
          icon: BitmapDescriptor.defaultMarker,
        ),
      );
    });
  }

  _onCameraMove(CameraPosition position) async{
    _lastMapPosition = position.target;
    final coordinates = new Coordinates(position.target.latitude, position.target.longitude);
    var addresses = await Geocoder.local.findAddressesFromCoordinates(coordinates);
    var first = addresses.first;

    setState(() {
      address = "${first.addressLine}";
    });
  }

Solution

  • Your mistake on this line onPressed: _onAddMarkerButtonPressed()

    since you are excuting your function whenever this widget is rendered to the view

    you have to pass it inside an arrow function like this

    onPressed: () => _onAddMarkerButtonPressed()