Hey team,
I have been at this for a bit now and just seeing if there is any easy way to get my custom markers to update on what the user moves or when the camera is moved. Any assistance would be greatly appreciated.
Hey team,
I have been at this for a bit now and just seeing if there is any easy way to get my custom markers to update on what the user moves or when the camera is moved. Any assistance would be greatly appreciated.
I have tried a listener, duplicating my loadMarkers into a future state as _location.onLocationChange.listen. The closest i got was it was updating the markers when i change a firebase record with a default marker but the custom marker wasn't showing and on click it didn't link.
// Automatic FlutterFlow imports import '/backend/backend.dart'; import '/backend/schema/structs/index.dart'; import '/flutter_flow/flutter_flow_theme.dart'; import '/flutter_flow/flutter_flow_util.dart'; import '/custom_code/widgets/index.dart'; // Imports other custom widgets import '/custom_code/actions/index.dart'; // Imports custom actions import '/flutter_flow/custom_functions.dart'; // Imports custom functions import 'package:flutter/material.dart'; // Begin custom widget code // DO NOT REMOVE OR MODIFY THE CODE ABOVE! // ignore: unnecessary_import // ignore: unnecessary_import import 'package:google_maps_flutter/google_maps_flutter.dart' as google_maps_flutter; import '/flutter_flow/lat_lng.dart' as latlng; import 'dart:async'; export 'dart:async' show Completer; export 'package:google_maps_flutter/google_maps_flutter.dart' hide LatLng; export '/flutter_flow/lat_lng.dart' show LatLng; import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; import 'dart:ui'; // ignore: unnecessary_import import 'package:cloud_firestore/cloud_firestore.dart'; import 'dart:typed_data'; import 'package:flutter/services.dart' show rootBundle; import 'package:http/http.dart' as http; import 'package:image/image.dart' as img; class FirestoreMap extends StatefulWidget { const FirestoreMap({ super.key, this.width, this.height, this.places, required this.centerLatitude, required this.centerLongitude, required this.showLocation, required this.showCompass, required this.showMapToolbar, required this.showTraffic, required this.allowZoom, required this.showZoomControls, required this.defaultZoom, this.mapStyleJson, this.onClickMarker, }); final double? width; final double? height; final List<LocationsRecord>? places; final double centerLatitude; final double centerLongitude; final bool showLocation; final bool showCompass; final bool showMapToolbar; final bool showTraffic; final bool allowZoom; final bool showZoomControls; final double defaultZoom; final Future Function(LocationsRecord? placeRow)? onClickMarker; final String? mapStyleJson; @override State<FirestoreMap> createState() => _FirestoreMapState(); } class _FirestoreMapState extends State<FirestoreMap> { Completer<google_maps_flutter.GoogleMapController> _controller = Completer(); Map<String, google_maps_flutter.BitmapDescriptor> _customIcons = {}; Set<google_maps_flutter.Marker> _markers = {}; // ignore: unused_field List<LocationsRecord> _list = []; // ignore: unused_field StreamSubscription? _locationsSubscription; late google_maps_flutter.LatLng _center; @override void initState() { super.initState(); _center = google_maps_flutter.LatLng( widget.centerLatitude, widget.centerLongitude); _loadMarkerIcons().then((_) { _listenToLocations(); }); } void _listenToLocations() { _locationsSubscription = FirebaseFirestore.instance .collection('locations') .snapshots() .listen((snapshot) { final locations = snapshot.docs .map((doc) => LocationsRecord.fromSnapshot(doc)) .toList(); setState(() { _list = locations; // Removed the call to _loadMarkerIcons() }); }); } Future<void> _loadMarkerIcons() async { Set<String> uniqueIconPaths = widget.places?.map((data) => data.coverImage).toSet() ?? {}; for (String urlString in uniqueIconPaths) { if (urlString.isNotEmpty) { // Fetch the bytes from the network URL using http package final response = await http.get(Uri.parse(urlString)); if (response.statusCode == 200) { // Decode the image from the bytes img.Image? image = img.decodeImage(response.bodyBytes); if (image != null) { // Resize the image img.Image thumbnail = img.copyResize(image, width: 30); // Set the desired size // Create the BitmapDescriptor from resized bytes final descriptor = google_maps_flutter.BitmapDescriptor.fromBytes( img.encodePng(thumbnail), ); // Store the descriptor with the URL as the key for later use with markers _customIcons[urlString] = descriptor; } else { print('Failed to decode image at $urlString.'); } } else { // Handle the case when the image is not retrieved from the network print( 'Failed to load image at $urlString, status code: ${response.statusCode}'); } } } _updateMarkers(); // Update markers once icons are loaded } void _updateMarkers() { setState(() { _markers = _createMarkers(); }); } void _onMapCreated(google_maps_flutter.GoogleMapController controller) { _controller.complete(controller); if (widget.mapStyleJson != null) { // Apply the map style if provided controller.setMapStyle(widget.mapStyleJson); } } Set<google_maps_flutter.Marker> _createMarkers() { var tmp = <google_maps_flutter.Marker>{}; for (int i = 0; i < (widget.places ?? []).length; i++) { var place = widget.places?[i]; final latlng.LatLng coordinates = latlng.LatLng( place?.tempAddress?.latitude ?? 0.0, place?.tempAddress?.longitude ?? 0.0); final google_maps_flutter.LatLng googleMapsLatLng = google_maps_flutter.LatLng( coordinates.latitude, coordinates.longitude); google_maps_flutter.BitmapDescriptor icon = _customIcons[place?.coverImage] ?? google_maps_flutter.BitmapDescriptor.defaultMarker; final google_maps_flutter.Marker marker = google_maps_flutter.Marker( markerId: google_maps_flutter.MarkerId('${place?.name ?? "Marker"}_$i'), position: googleMapsLatLng, icon: icon, infoWindow: google_maps_flutter.InfoWindow( title: place?.name, snippet: place?.description), onTap: () async { // Animate camera to the marker's position when tapped final google_maps_flutter.GoogleMapController controller = await _controller.future; controller .animateCamera(google_maps_flutter.CameraUpdate.newCameraPosition( google_maps_flutter.CameraPosition( target: googleMapsLatLng, zoom: 15.0, // Adjust zoom level as needed ), )); // Execute additional callback if provided final callback = widget.onClickMarker; if (callback != null) { await callback(place); } }, ); tmp.add(marker); } return tmp; } Future<void> _fetchAndUpdateMarkers() async { final google_maps_flutter.GoogleMapController controller = await _controller.future; // Optionally, get the current map bounds to fetch data accordingly // This part depends on how you want to fetch new data based on map position // Example: Fetch new data (assuming this requires asynchronous operation) await _fetchDataBasedOnMapPosition(controller); // Example fetching data might involve setting state for _list or _markers setState(() { // Assuming _createMarkers() uses the updated data to create new markers _markers = _createMarkers(); }); } // Example stub for fetching data based on map position (modify as needed) Future<void> _fetchDataBasedOnMapPosition( google_maps_flutter.GoogleMapController controller) async { // Your data fetching logic here // For example, adjust the query to Firestore based on the map's current position // Or, update the widget.places with new data based on current map bounds } @override Widget build(BuildContext context) { return google_maps_flutter.GoogleMap( onMapCreated: _onMapCreated, onCameraMove: (cameraPosition) { // Optional: If you want to update markers as the camera moves (real-time) }, onCameraIdle: _fetchAndUpdateMarkers, zoomGesturesEnabled: widget.allowZoom, zoomControlsEnabled: widget.showZoomControls, myLocationEnabled: widget.showLocation, myLocationButtonEnabled: true, compassEnabled: widget.showCompass, mapToolbarEnabled: widget.showMapToolbar, mapType: google_maps_flutter.MapType.normal, trafficEnabled: widget.showTraffic, initialCameraPosition: google_maps_flutter.CameraPosition( target: _center, zoom: widget.defaultZoom, ), markers: _markers, ); } }