'Fix google map marker in center

In my flutter app. I am using google_maps_plugin . The link is https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter . I want to fix the marker in center of map without movable after draging the map. I want it likes http://jsfiddle.net/UuDA6/ In my code i am using MarkerOption for placing the marker.

    MarkerOptions options = new MarkerOptions(   
        alpha: 1.0,
        anchor: Offset(0.5, 1.0),
        consumeTapEvents: false,
        draggable: false,
        flat: false,
        icon: BitmapDescriptor.defaultMarker,
        infoWindowAnchor: Offset(0.5, 0.0),
        infoWindowText: InfoWindowText.noText,
        position: LatLng(17.411439, 78.5486697),
        rotation: 0.0,
        visible: true,
        zIndex: 0.0,
    );

But in the position i want to know how to give the center of map.

If any one have idea about it please share it.



Solution 1:[1]

Actually with new update of google_maps_flutter: ^0.4.0 we can achieve above requirement easily.

This is the demo link.

Map<MarkerId, Marker> _markers = <MarkerId, Marker>{};
int _markerIdCounter = 0;
Completer<GoogleMapController> _mapController = Completer();

Container(
    width: MediaQuery.of(context).size.width,
    height: MediaQuery.of(context).size.height,
    child: GoogleMap(
      markers: Set<Marker>.of(_markers.values),
      onMapCreated: _onMapCreated,
      initialCameraPosition: CameraPosition(
        target: Constants.LOCATION_SRI_LANKA,
        zoom: 12.0,
      ),
      myLocationEnabled: true,
      onCameraMove: (CameraPosition position) {
        if(_markers.length > 0) {
          MarkerId markerId = MarkerId(_markerIdVal());
          Marker marker = _markers[markerId];
          Marker updatedMarker = marker.copyWith(
            positionParam: position.target,
          );

          setState(() {
            _markers[markerId] = updatedMarker;
          });
        }
      },
    ),
  )

void _onMapCreated(GoogleMapController controller) async {
  _mapController.complete(controller);
  if ([INITIAL_LOCATION] != null) {
    MarkerId markerId = MarkerId(_markerIdVal());
    LatLng position = [INITIAL_LOCATION];
    Marker marker = Marker(
      markerId: markerId,
      position: position,
      draggable: false,
    );
    setState(() {
      _markers[markerId] = marker;
    });

    Future.delayed(Duration(seconds: 1), () async {
      GoogleMapController controller = await _mapController.future;
      controller.animateCamera(
        CameraUpdate.newCameraPosition(
          CameraPosition(
            target: position,
            zoom: 17.0,
          ),
        ),
      );
    });
  }
}

String _markerIdVal({bool increment = false}) {
  String val = 'marker_id_$_markerIdCounter';
  if (increment) _markerIdCounter++;
  return val;
}

Solution 2:[2]

This is based on the @Joe answer but it has more accurated pin position and no other class is required:

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

return new Stack(
    alignment: Alignment(0.0, 0.0),
    children: <Widget>[
      new Container(
        width: mapWidth,
        height: mapHeight,
        child: _googleMap
      ),
      new Positioned(
        top: (mapHeight - iconSize)/ 2,
        right: (mapWidth - iconSize)/ 2,
        child: new Icon(Icons.person_pin_circle, size: iconSize),
      )
  ]);

This solution don't require to repaint the entire Screen (no setState call) when user update the position. You won't see that weird marker "movement".

Solution 3:[3]

The right answer is to use Stack and overlay marker pin on map. if you try to put marker on map using GoogleMaps markers property, you have to update marker position on CameraMove and call setState which add latency on redrawing maker.

compare two approaches:

enter image description here

class StoreLocationMap extends StatefulWidget {
  final Coordinate userLocation;
  const StoreLocationMap({Key? key, required this.userLocation})
      : super(key: key);

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

class _StoreLocationMapState extends State<StoreLocationMap> {
  final List<Marker> _markers = [];
  @override
  Widget build(BuildContext context) {
    return Stack(
      alignment: Alignment.center,
      children: [
        GoogleMap(
          initialCameraPosition: CameraPosition(
              target: LatLng(
                  widget.userLocation.latitude, widget.userLocation.longitude),
              zoom: 14),

        
          markers: _markers.toSet(),
        
          onMapCreated: (controller) {
            final marker = Marker(
              markerId: MarkerId('0'),
              position: LatLng(
                  widget.userLocation.latitude, widget.userLocation.longitude),
              
            );

            _markers.add(marker);
          },
          onCameraMove: (position) {
            setState(() {
              _markers.first =
                  _markers.first.copyWith(positionParam: position.target);
            });
          },
        ),
        Image.asset(
          'assets/images/delivery-area-start-pin.png',
          frameBuilder: (context, child, frame, wasSynchronouslyLoaded) {
            return Transform.translate(
              offset: const Offset(8, -37),
              child: child,
            );
          },
        )
      ],
    );
  }
}

As my custom marker has shadow and is not symmetric, I used Transform widget to translate custom marker to point to right location.

How to get map center coordinate? or center maker position?

User onCameraMove to get map center position:

onCameraMove: (position) {
            print(position.target);
          },

Solution 4:[4]

It is possible using stack. The code is shown below.

Stack(
children: <Widget>[
GoogleMap(
onMapCreated: _onMapCreated,
),
InfoView()                  
 ],)

The InfoView is

class InfoView extends State<AppPage> {
    const InfoView({
        Key key,
        })  : super(key: key);

   @override
    Widget build(BuildContext context) {
    return new Align(
            alignment: Alignment.center,
            child: new Icon(Icons.person_pin_circle, size: 40.0),

        );
    }
}

Then the _onMapCreated is

void _onMapCreated(GoogleMapController controller) {
        setState(() {
        mapController = controller;
            mapController.animateCamera(CameraUpdate.newCameraPosition(
                    CameraPosition(
                    bearing: 270.0,
                    target: LatLng(lattitude, longitude),
                    tilt: 30.0,
                    zoom: 17.0,
                    ),
                ));
        });
    }
    }

This stack class is useful if you want to overlap several children in a simple way, for example having some text and an image, overlaid with a gradient and a button attached to the bottom.

Solution 5:[5]

I recommend to you to try this new Flutter package https://pub.dev/packages/flutter_animarker

Solution 6:[6]

Use Stack and IgnorePointer to ignore touches on your widget

Stack(
  children: <Widget>[
    GoogleMap(
      ....
    ),
    Center(
     child: IgnorePointer(
       child: ...
     )
    )               
  ]
)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Pasan Randula Eramusugoda
Solution 2 Alexis Gamarra
Solution 3 Hashem Aboonajmi
Solution 4 Joe
Solution 5 Gauris Javier
Solution 6 Tamás Sengel