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);
}
}
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;
});
},