google_maps_widget icon indicating copy to clipboard operation
google_maps_widget copied to clipboard

Help Needed - is it possible to show info windows on all markers by default?

Open rajesh-h opened this issue 1 year ago • 2 comments

Hi @rithik-dev ,

Since you know more about the google maps package, may I ask is it possible to show infoWindow for all markers by default?

I tried below that is looping through markers and showInfoWindow but that shows only the last marker's info window.

Thank you very much for your help.

this is how I try:

// // Show the info windows for all markers
    for (final marker in _markers) {
      print(marker.infoWindow.title);
      await Future.delayed(const Duration(milliseconds: 300));
      _googleMapController.showMarkerInfoWindow(marker.markerId);
     
    }

my full code is below:

import 'dart:async';
import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:ugv_fe/api/backend_api.dart';
import 'package:ugv_fe/models/vehicle2.dart';
import 'package:ugv_fe/pages/vehicles_list.dart';
import 'package:ugv_fe/provider/theme_provider.dart';

class LandingPage extends StatefulWidget {
  const LandingPage({Key? key}) : super(key: key);

  @override
  State<LandingPage> createState() => _LandingPageState();
}

class _LandingPageState extends State<LandingPage> {
  Timer? _timer;
  bool _isPageOpen = true;

  int selectedVehicleIndex = 0;
  static LatLng current_Camera_posistion = const LatLng(0, 0);
  String? _mapStyle;
  late GoogleMapController _googleMapController;
  static List<Vehicle> allVehiclesList = [];
  bool showVehiclesList = false;
  bool markersLoading = false;
  bool vehiclesLoaded = false;
  // final Map<String, Marker> _markers = {};
  final List<Marker> _markers = [];
  int markerFlag = -1;
  // final Set<Marker>? _markers = <Marker>{};
  BitmapDescriptor? activeMarker;
  BitmapDescriptor? offlineMarker;
  BitmapDescriptor? alertMarker;
  BitmapDescriptor? activeMarkerSelected;
  BitmapDescriptor? offlineMarkerSelected;
  BitmapDescriptor? alertMarkerSelected;

  Future<BitmapDescriptor> getIcon(
      {required String imagePath, required int width}) async {
    final Uint8List markerIcon = await getBytesFromAsset(imagePath, width);
    BitmapDescriptor icon = BitmapDescriptor.fromBytes(markerIcon);
    return icon;
  }

  Future<Uint8List> getBytesFromAsset(String path, int width) async {
    ByteData data = await rootBundle.load(path);
    Codec codec = await instantiateImageCodec(data.buffer.asUint8List(),
        targetWidth: width);
    FrameInfo fi = await codec.getNextFrame();
    return (await fi.image.toByteData(format: ImageByteFormat.png))!
        .buffer
        .asUint8List();
  }

  Future<void> setMarkerIcon() async {
    print("Trying to setup Marker");
    print(markersLoading);
    activeMarker =
        await getIcon(imagePath: 'assets/images/marker_online.png', width: 100);
    activeMarkerSelected =
        await getIcon(imagePath: 'assets/images/marker_online.png', width: 130);
 
    offlineMarker = await getIcon(
        imagePath: 'assets/images/marker_offline.png', width: 100);
    offlineMarkerSelected = await getIcon(
        imagePath: 'assets/images/marker_offline.png', width: 130);
  
    alertMarker =
        await getIcon(imagePath: 'assets/images/marker_alert.png', width: 100);
    alertMarkerSelected =
        await getIcon(imagePath: 'assets/images/marker_alert.png', width: 130);

    setState(() {
      markersLoading = true;
    });
  }

  static final CameraPosition _kGooglePlex = CameraPosition(

    target: LatLng(double.tryParse(allVehiclesList[0].vehicleLatitude!) ?? 0.0,
        double.tryParse(allVehiclesList[0].vehicleLongitude!) ?? 0.0),
    zoom: 18,
  );

  Future<void> _onMapCreated(GoogleMapController controller) async {

    _googleMapController = controller;
    setState(() {
      _markers.clear();
      print("VehiclesList inside onMapCreated");
      print(allVehiclesList);
      var cnt = 0;
      for (final vehicle in allVehiclesList) {
        int idMarker = cnt;
        _markers.add(Marker(
          consumeTapEvents: true,
          icon: (vehicle.vehicleIsOnline! &&
                  vehicle.vehicleCurrentStatus == 'Active')
              ? activeMarker!
              : (vehicle.vehicleCurrentStatus == 'Alert')
                  ? alertMarker!
                  : offlineMarker!,
          markerId: MarkerId(idMarker.toString()),
          position: LatLng(double.tryParse(vehicle.vehicleLatitude!)!,
              double.tryParse(vehicle.vehicleLongitude!)!),
          infoWindow: InfoWindow(
            title: vehicle.vehicleName,
       
          ),
          onTap: () {
            if (markerFlag != idMarker) {
              setState(() {
                // resetMarkers();

                if (markerFlag != -1) {
                  Vehicle oldSelectedVehicle = allVehiclesList[markerFlag];
                  _markers[markerFlag] = _markers[markerFlag].copyWith(
                    iconParam: (oldSelectedVehicle.vehicleIsOnline! &&
                            oldSelectedVehicle.vehicleCurrentStatus == 'Active')
                        ? activeMarker!
                        : (oldSelectedVehicle.vehicleCurrentStatus == 'Alert')
                            ? alertMarker!
                            : offlineMarker!,
                  );
                }
                _markers[idMarker] = _markers[idMarker].copyWith(
                  iconParam: (vehicle.vehicleIsOnline! &&
                          vehicle.vehicleCurrentStatus == 'Active')
                      ? activeMarkerSelected!
                      : (vehicle.vehicleCurrentStatus == 'Alert')
                          ? alertMarkerSelected!
                          : offlineMarkerSelected!,
                );
                markerFlag = idMarker;
              });
            }
            showVehiclesListPopup(idMarker);
          },
        ));
        // _googleMapController
        //     .showMarkerInfoWindow(MarkerId(idMarker.toString()));
        // _markers[vehicle.vehicleName] = marker;
        cnt += 1;
      }
    });
    // // Show the info windows for all markers
    for (final marker in _markers) {
      print(marker.infoWindow.title);
      await Future.delayed(const Duration(milliseconds: 300));
      _googleMapController.showMarkerInfoWindow(marker.markerId);
     
    }
  }

  getData() async {
    var result = await CallApi().getVehicles();
    allVehiclesList = result;
    print("Inside Get Data");
    print(allVehiclesList);
    for (final vehicle in allVehiclesList) {
      print(vehicle.vehicleName);
    }
    setState(() {
      vehiclesLoaded = true;
    });
  }

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    getData();
    setMarkerIcon();
    rootBundle.loadString('assets/map_style.txt').then((string) {
      _mapStyle = string;
    });
    _timer = Timer.periodic(const Duration(seconds: 30), (Timer t) {
      if (_isPageOpen) {
        reloadGetData();
      } else {
        _timer?.cancel();
      }
    });
  }

  @override
  void dispose() {
    _isPageOpen = false;
    _timer?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        !markersLoading || !vehiclesLoaded
            ? const SpinKitWave(size: 32, color: AppThemes.appCommonRedColor)
            : GoogleMap(
                onTap: (value) {
                  setState(() {
                 
                    markerFlag = -1;
                  });
                },
                mapType: MapType.hybrid,
                onMapCreated: _onMapCreated,
                initialCameraPosition: _kGooglePlex,
                markers: _markers.toSet(),
                mapToolbarEnabled: false,
                zoomControlsEnabled: false,
                padding: const EdgeInsets.all(150),
                onCameraMove: (CameraPosition position) {
                  setState(() {
                    current_Camera_posistion = LatLng(
                        position.target.latitude, position.target.longitude);
                  });
                },
              ),

        Positioned(
          top: 20,
          left: 5,
          child: Card(
            elevation: 20,
            child: SizedBox(
              // color: const Color(0xFFFAFAFA),
              width: 40,
              height: 100,
              child: Column(
                children: <Widget>[
                  IconButton(
                      icon: const Icon(Icons.add),
                      onPressed: () async {
                        var currentZoomLevel =
                            await _googleMapController.getZoomLevel();
                        print(currentZoomLevel);

                        currentZoomLevel = currentZoomLevel + 2;
                        _googleMapController.animateCamera(
                          CameraUpdate.newCameraPosition(
                            CameraPosition(
                              target: current_Camera_posistion,
                              zoom: currentZoomLevel,
                            ),
                          ),
                        );
                      }),
                  const SizedBox(height: 2),
                  IconButton(
                      icon: const Icon(Icons.remove),
                      onPressed: () async {
                        var currentZoomLevel =
                            await _googleMapController.getZoomLevel();
                        print(currentZoomLevel);
                        currentZoomLevel = currentZoomLevel - 2;
                        if (currentZoomLevel < 0) currentZoomLevel = 0;
                        _googleMapController.animateCamera(
                          CameraUpdate.newCameraPosition(
                            CameraPosition(
                              target: current_Camera_posistion,
                              zoom: currentZoomLevel,
                            ),
                          ),
                        );
                      }),
                ],
              ),
            ),
          ),
        ),
        // Positioned(
        //     top: 20,
        //     right: 5,
        //     child: FloatingActionButton(
        //         mini: true,
        //         backgroundColor: AppThemes.appCommonBGColor,
        //         child: const Icon(Icons.refresh_rounded),
        //         onPressed: () {
        //           print('Pressed reload');
        //           reloadGetData();
        //         })),
        showVehiclesList
            ? Positioned(
                right: 10,
                bottom: MediaQuery.of(context).size.height * 0.5 + 62,
                child: FloatingActionButton(
                    child: const Icon(
                      Icons.close,
                      color: AppThemes.appCommonRedColor,
                    ),
                    backgroundColor:
                        Theme.of(context).colorScheme.surface.withOpacity(0.7),
                    mini: true,
                    onPressed: hideVehiclesListPopup),
              )
            : const SizedBox.shrink(),
        showVehiclesList
            ? Positioned(
                left: 10,
                right: 10,
                bottom: 58,
                child: VehiclesList(
                  vehiclesList: allVehiclesList,
                  selectedVehicleIndex: selectedVehicleIndex,
                ))
            : const SizedBox.shrink(),
      ],
    );
  }

  showVehiclesListPopup(int index) {
    setState(() {
      showVehiclesList = true;
      selectedVehicleIndex = index;
      // print("I am here");
      // print(vehicleId);

      // selectedVehicleIndex = allVehiclesList
      //     .indexWhere((vehicle) => vehicle.vehicleId == vehicleId);
      // print(selectedVehicleIndex);
    });
  }

  hideVehiclesListPopup() {
    setState(() {
      showVehiclesList = false;
    });
  }

  resetMarkers() {
    var index = 0;
    setState(() {
      for (final vehicle in allVehiclesList) {
        print(vehicle.vehicleId);
        _markers[index] = _markers[index].copyWith(
          iconParam: (vehicle.vehicleIsOnline! &&
                  vehicle.vehicleCurrentStatus == 'Active')
              ? activeMarker!
              : (vehicle.vehicleCurrentStatus == 'Alert')
                  ? alertMarker!
                  : offlineMarker!,
        );
      }
    });
  }

  Future<void> reloadGetData() async {
    await getData();
    await setMarkerIcon();
    await _onMapCreated(_googleMapController);
    print('Data Reloaded Landing Page');
    setState(() {
      // Your code here
    });
  }
}

rajesh-h avatar Jul 11 '23 05:07 rajesh-h

Hi @rajesh-h, according to the documentation:

An info window allows you to display information to the user when they tap on a marker. Only one info window is displayed at a time. If a user clicks on a marker, the current info window will be closed and the new info window will be displayed.

So, this is the default behavior.

rithik-dev avatar Jul 11 '23 06:07 rithik-dev

You can try using label_marker. Looks like this package allows to show multiple markers at the same time. It does not look like the package needs an update for this, as it exposes an extension method on the set of markers, addLabelMarker.

You can try using this, and see if it works...

rithik-dev avatar Jul 11 '23 07:07 rithik-dev