fluttergoogle-mapsgoogle-maps-markersmarkergoogle-maps-flutter

Flutter - Trigger Visibility of Google Map Marker via CheckboxListTile


I've built simple application in Flutter. I have simple 2 containers. 1st one has 4 CheckboxListTiles and 2nd one has Google Map plugin with markers.

All CheckboxListTile keys and all marker ids are matching. You can see in my code below.

What I want is; when I click any CheckboxListTile, I want to trigger its related marker's visibility.

Regarding this answer , I used .copyWith , but still I can't change visibility. What am I missing ?

Here it is my code:

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

class TestScreen extends StatefulWidget {
  @override
  _TestScreenState createState() => _TestScreenState();
}

class _TestScreenState extends State<TestScreen> {
  List<Marker> _markers = [];
  late BitmapDescriptor pinLocationIcon;
  Completer<GoogleMapController> _controller = Completer();

  final List<Circle> _newcircles = [];

  Map<String, bool> myValues = {
    "W": true,
    "T": true,
    "A": true,
    "K": true,
  };

  late BitmapDescriptor pinLocationAIcon;
  List<Marker> _aMarkers = [];
  late BitmapDescriptor pinLocationKIcon;
  List<Marker> _kMarkers = [];
  late BitmapDescriptor pinLocationTIcon;
  List<Marker> _tMarkers = [];
  late BitmapDescriptor pinLocationWIcon;
  List<Marker> _wMarkers = [];

  @override
  void initState() {
    super.initState();
    setCustomMapPin();
  }
  void setCustomMapPin() async {
    pinLocationIcon = await BitmapDescriptor.fromAssetImage(
        const ImageConfiguration(size: Size(10, 10)),'images/marker-trans-150.png');
    pinLocationAIcon = await BitmapDescriptor.fromAssetImage(
        const ImageConfiguration(size: Size(10, 10)),'images/a-150.png');
    pinLocationKIcon = await BitmapDescriptor.fromAssetImage(
        const ImageConfiguration(size: Size(10, 10)),'images/k-150.png');
    pinLocationTIcon = await BitmapDescriptor.fromAssetImage(
        const ImageConfiguration(size: Size(10, 10)),'images/t-150.png');
    pinLocationWIcon = await BitmapDescriptor.fromAssetImage(
        const ImageConfiguration(size: Size(10, 10)),'images/w-150.png');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.green,
      body: Column(
        children: [
          Container(
            margin: EdgeInsets.only(left: 5, right: 5, top: 5),
            decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(5))),
            height: 100.0,
            child: GridView.count(
              mainAxisSpacing: 0.0,
              crossAxisSpacing: 5.0,
              childAspectRatio: 5.0,
              crossAxisCount: 2,
              children: myValues.keys.map((String key) {
                return CheckboxListTile(
                  activeColor: Colors.greenAccent,
                  title: Text(key),
                  value: myValues[key],
                  selected: myValues[key]!,
                  onChanged: (value) {
                    setState(() {
                      myValues[key] = value!;
                      _markers.forEach((marker) {
                        if(marker.markerId.value == key) {
                          final Marker _marker = marker;
                          marker = _marker.copyWith(
                            visibleParam: !_marker.visible,
                          );
                        }
                      });
                    });
                  },
                );
              }).toList(),
            ),
          ),
          Container(
            margin: EdgeInsets.only(left: 5, right: 5, top: 5),
            decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(5))),
            height: 300.0,
            child: ClipRRect(
              borderRadius: BorderRadius.only(
                topLeft: Radius.circular(5),
                topRight: Radius.circular(5),
                bottomRight: Radius.circular(5),
                bottomLeft: Radius.circular(5),
              ),
              child: GoogleMap(
                circles: _newcircles.toSet(),
                myLocationEnabled: true,
                myLocationButtonEnabled: true,
                initialCameraPosition: CameraPosition(
                    target: LatLng(
                        50.505050, 50.505050),
                    zoom: 10),
                markers: _markers.toSet(),
                onMapCreated: (controller) {
                  _controller.complete(controller);
                  _addStoresToMarkers();
                },
                onCameraMove: (position) {
                  setState(() {

                  });
                },
              ),
            ),
          )
        ],
      ),
    );
  }

  _addAMarker(){
    _aMarkers.add(Marker(
      visible: true,
      markerId: MarkerId("A"),
      draggable: false,
      infoWindow: InfoWindow(title: "A", snippet: "A"),
      position: LatLng(50.515050, 50.495050),
      icon: pinLocationAIcon,
    ));
  }
  _addKMarker(){
    _kMarkers.add(Marker(
      visible: true,
      markerId: MarkerId("K"),
      draggable: false,
      infoWindow: InfoWindow(title: "K", snippet: "K"),
      position: LatLng(50.525050, 50.485050),
      icon: pinLocationKIcon,
    ));
  }
  _addTMarker(){
    _tMarkers.add(Marker(
      visible: true,
      markerId: MarkerId("T"),
      draggable: false,
      infoWindow: InfoWindow(title: "T", snippet: "T"),
      position: LatLng(50.535050, 50.475050),
      icon: pinLocationTIcon,
    ));
  }
  _addWMarker(){
    _wMarkers.add(Marker(
      visible: true,
      markerId: MarkerId("W"),
      draggable: false,
      infoWindow: InfoWindow(title: "W", snippet: "W"),
      position: LatLng(50.545050, 50.465050),
      icon: pinLocationWIcon,
    ));
  }

  _addStoresToMarkers() {
    _addAMarker();
    _addKMarker();
    _addWMarker();
    _addTMarker();

    _markers.addAll(_aMarkers);
    _markers.addAll(_tMarkers);
    _markers.addAll(_kMarkers);
    _markers.addAll(_wMarkers);
  }
}


Solution

  • I suggest that you create a new array for the updated markers, and assign it to the _markers member. When you just modify the items in an array (like you do in your code with _markers), the array's value itself is not changed. That's why setState does not trigger a rebuild.

    Try the following code in onChanged:

    onChanged: (value) {
      setState(() {
        myValues[key] = value!;
        final newMarkers = <Marker>[];
        for (var marker in _markers) {
          if (marker.markerId.value == key) {
            newMarkers.add(marker.copyWith(
              visibleParam: !marker.visible,
            ));
          } else {
            newMarkers.add(marker);
          }
        }
        _markers = newMarkers;
      });
    },