Custom Marker và Info Window trong GoogleMap Flutter - Tập cuối
December 21, 2022
2 min
Hế lô các bẹn đã đến với phần 2 Custom marker và Info window trong Flutter. Tại phần trước, mình đã hướng dẫn các bạn cách để convert ảnh sang bitmap để sử dụng thay thế marker trong Google map. Hôm nay mình sẽ hướng dẫn các bạn cách để Group Marker
như thế này nhé:
Lưu ý: Mình sẽ comment giải thích bên trong code luôn nhé
static Future<BitmapDescriptor> _bitmapGroup(String text,int size,) async {/// Đoạn này là mình define Canvas để chuẩn bị vẽ và khởi tạo loại màu để fill lên vòng trònfinal ui.PictureRecorder pictureRecorder = ui.PictureRecorder();final Canvas canvas = Canvas(pictureRecorder);final Paint paint1 = Paint()..color = Colors.orangeAccent;final Paint paint2 = Paint()..color = Colors.white;/// Chỗ này là hàm có sẵn của Canvas giúp vẽ hình tròn/// Ở đây mình vẽ 3 hình tròn để lấy được border bên ngoài hình tròn/// Mình chỉ việc đưa vào:/// Offset: Tọa độ (dx,dy)/// size/2.0: bán kính hình tròn/// paint1: màu sẽ fill lên hình tròn đócanvas.drawCircle(Offset(size / 2, size / 2), size / 2.0, paint1);canvas.drawCircle(Offset(size / 2, size / 2), size / 2.0, paint2);canvas.drawCircle(Offset(size / 2, size / 2), size / 2.2, paint1);TextPainter painter = TextPainter(textDirection: TextDirection.ltr);painter.text = TextSpan(text: text,style: TextStyle(fontSize: size / 3,color: Colors.white,fontWeight: FontWeight.normal),);painter.layout();/// Xong rồi gán vào hàm paint để vẽ hình tròn với text ở giữapainter.paint(canvas,Offset(size / 2 - painter.width / 2, size / 2 - painter.height / 2),);/// Chỗ này là convert sang dạng ảnh giống như hàm convert svg tại tập 1 thôiui.Image img = await pictureRecorder.endRecording().toImage(size, size);ByteData? data = await img.toByteData(format: ui.ImageByteFormat.png);return BitmapDescriptor.fromBytes(data!.buffer.asUint8List());}
ClusterItem
nhé, thằng này sẽ phải override lại location
để lấy vị trí cho Group markerclass PlaceModel with ClusterItem {final String id;final String name;final LatLng latLng;PlaceModel(this.id, {required this.name,required this.latLng,});@overrideLatLng get location => latLng;}
_initClusterManager
ClusterManager _initClusterManager() {return ClusterManager<PlaceModel>(_mapController.places, // Đưa vào List Place_updateMarkers, // Update lại MarkermarkerBuilder: _markerBuilder, // Build marker khi có 1 phần tử hoặc Group nhiều phần tử);}void _updateMarkers(Set<Marker> markers) {setState(() {_mapController.markers = markers;});}
_markerBuilder
sẽ là hàm để xác định Marker có hình dạng như nào ( Hình tròn hay là cái cọc cô đơn trong mùa đông giá lạnh)Future<Marker> Function(Cluster<PlaceModel>) get _markerBuilder =>(cluster) async {// Chỗ này mình mặc dù library trả về `items` là List// nhưng chỉ có 1 phần tử nên mình lấy phần tử đầu tiên luônfinal item = cluster.items.toList().first;// Chỗ này là gán Marker bình thường thôireturn Marker(markerId: MarkerId(cluster.getId()),position: cluster.location,icon: await BitmapConvert.convertMarkerBitmap(context,120,text: cluster.isMultiple ? cluster.count.toString() : null,id: item.id,),infoWindow: InfoWindow(title: item.name),);};
// Đảm nhiệm check nếu Cluster truyền vào từ bên kia có text// Thì sẽ Group không thì để Marker custom như tập 1static Future<BitmapDescriptor> convertMarkerBitmap(BuildContext context,int size, {String? text,required int id,}) async {if (text != null) {return await _bitmapGroup(text, size);} else {return await _bitmapSvg(context, id);}}
_initClusterManager
đã tạo ở trênlate ClusterManager _manager;@overridevoid initState() { super.initState();_mapController.loadPlace();_manager = _initClusterManager();}
GoogleMap(markers: _mapController.markers,initialCameraPosition: const CameraPosition(target: LatLng(35.226642, 136.735311),zoom: 15.0,),// Chỗ này là hàm tạo Map, mình sẽ set cluster Id tương ứng với mapIdonMapCreated: (GoogleMapController controller) {_manager.setMapId(controller.mapId);},// Hàm này là khi camera thay đổi thì sẽ vẽ lại những view Group tương ứngonCameraMove: (position) {_manager.onCameraMove(position);},// Hàm này update lại Map đã được vẽ lại khi mình dừng di chuyển cameraonCameraIdle: () {_manager.updateMap();},);