尝试使用用户 imageURL 及其名称为 flutter 中的谷歌地图构建自定义标记。就像下图一样,但我对定制油漆不太熟悉。我只知道简单的形状。 我已经按照 this 构建了像给定的图像。
代码:
Future<BitmapDescriptor> getMarkerImage(NearbyUsers user) async {
if (user.image != null) {
final File markerImageFile =
await DefaultCacheManager().getSingleFile(user.image);
Size s = user.userId == profileData.userId.toString()
? Size(150, 150)
: Size(120, 120);
var icon = await getMarkerIcon(markerImageFile.path, s, user);
return icon;
} else {
return BitmapDescriptor.defaultMarker;
}
}
Future<BitmapDescriptor> getMarkerIcon(
String imagePath, Size size, NearbyUsers user) async {
final ui.PictureRecorder pictureRecorder = ui.PictureRecorder();
final Canvas canvas = Canvas(pictureRecorder);
final Radius radius = Radius.circular(size.width / 2);
final Paint nameTagPaint = Paint()..color = MyTheme.primaryColor;
final double nameTagWidth = 40.0;
final Paint shadowPaint = Paint()
..color = MyTheme.primaryColor.withAlpha(120);
final double shadowWidth = 15.0;
final Paint borderPaint = Paint()..color = Colors.white;
final double borderWidth = 3.0;
final double imageOffset = shadowWidth + borderWidth;
// Add shadow circle
canvas.drawRRect(
RRect.fromRectAndCorners(
Rect.fromLTWH(0.0, 0.0, size.width, size.height),
topLeft: radius,
topRight: radius,
bottomLeft: radius,
bottomRight: radius,
),
shadowPaint);
// Add border circle
canvas.drawRRect(
RRect.fromRectAndCorners(
Rect.fromLTWH(shadowWidth, shadowWidth,
size.width - (shadowWidth * 2), size.height - (shadowWidth * 2)),
topLeft: radius,
topRight: radius,
bottomLeft: radius,
bottomRight: radius,
),
borderPaint);
// Name tag BG
canvas.drawRRect(
RRect.fromRectAndCorners(
Rect.fromCircle(center: Offset(nameTagWidth/2,nameTagWidth/2), radius: size.height *0.4 ),
topLeft: Radius.circular(8),
topRight: Radius.circular(8),
bottomLeft: Radius.circular(8),
bottomRight: Radius.circular(8),
),
nameTagPaint);
// Add Name text
TextPainter textPainter = TextPainter(textDirection: TextDirection.ltr);
textPainter.text = TextSpan(
text: '${user.fname} ${user.lname}',
style: TextStyle(fontSize: 20.0, color: Colors.white),
);
textPainter.layout();
textPainter.paint(
canvas,
Offset(1.0, 1.0),
// Offset(size.width - nameTagWidth / 2 - textPainter.width / 2,
// nameTagWidth / 2 - textPainter.height / 2)
);
// Oval for the image
Rect oval = Rect.fromLTWH(imageOffset, imageOffset,
size.width - (imageOffset * 2), size.height - (imageOffset * 2));
// Add path for oval image
canvas.clipPath(Path()..addOval(oval));
// Add image
ui.Image image = await getImageFromPath(
imagePath); // Alternatively use your own method to get the image
paintImage(canvas: canvas, image: image, rect: oval, fit: BoxFit.fitWidth);
// Convert canvas to image
final ui.Image markerAsImage = await pictureRecorder
.endRecording()
.toImage(size.width.toInt(), size.height.toInt());
// Convert image to bytes
final ByteData byteData =
await markerAsImage.toByteData(format: ui.ImageByteFormat.png);
final Uint8List uint8List = byteData.buffer.asUint8List();
return BitmapDescriptor.fromBytes(uint8List);
}
Future<ui.Image> getImageFromPath(String imagePath) async {
File imageFile = File(imagePath);
Uint8List imageBytes = imageFile.readAsBytesSync();
final Completer<ui.Image> completer = new Completer();
ui.decodeImageFromList(imageBytes, (ui.Image img) {
return completer.complete(img);
});
return completer.future;
}
输出:
经过长期研究,现在我能够理解一点点颤振自定义画家、画家或画布,无论我们如何称呼它。
但我仍然对设置阴影圆圈图像的偏移量感到愚蠢,并且无法根据给定的大小给它们动态偏移量。现在只给出静态偏移。请暂时忽略这一点。
完整代码:
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:upstanders/global/theme/colors.dart';
class MapSample extends StatefulWidget {
@override
_MapSampleState createState() => _MapSampleState();
}
class _MapSampleState extends State<MapSample> {
BitmapDescriptor customIcon;
Set<Marker> markers = {};
Future<BitmapDescriptor> createCustomMarkerBitmapWithNameAndImage(
String imagePath, Size size, String name) async {
TextSpan span = new TextSpan(
style: new TextStyle(
height: 1.2,
color: Colors.black,
fontSize: 30.0,
fontWeight: FontWeight.bold,
),
text: name);
TextPainter tp = new TextPainter(
text: span,
textAlign: TextAlign.center,
textDirection: TextDirection.ltr,
);
tp.layout();
ui.PictureRecorder recorder = new ui.PictureRecorder();
Canvas canvas = new Canvas(recorder);
final double shadowWidth = 15.0;
final double borderWidth = 3.0;
final double imageOffset = shadowWidth + borderWidth;
final Radius radius = Radius.circular(size.width / 2);
final Paint shadowCirclePaint = Paint()
..color = MyTheme.primaryColor.withAlpha(180);
// Add shadow circle
canvas.drawRRect(
RRect.fromRectAndCorners(
Rect.fromLTWH(
size.width / 8, size.width / 2, size.width, size.height),
topLeft: radius,
topRight: radius,
bottomLeft: radius,
bottomRight: radius,
),
shadowCirclePaint);
// TEXT BOX BACKGROUND
Paint textBgBoxPaint = Paint()..color = MyTheme.primaryColor;
Rect rect = Rect.fromLTWH(
0,
0,
tp.width + 35,
50,
);
canvas.drawRRect(
RRect.fromRectAndRadius(rect, Radius.circular(10.0)),
textBgBoxPaint,
);
//ADD TEXT WITH ALIGN TO CANVAS
tp.paint(canvas, new Offset(20.0, 5.0));
/* Do your painting of the custom icon here, including drawing text, shapes, etc. */
Rect oval = Rect.fromLTWH(35, 78, size.width - (imageOffset * 2),
size.height - (imageOffset * 2));
// ADD PATH TO OVAL IMAGE
canvas.clipPath(Path()..addOval(oval));
ui.Image image = await getImageFromPath(
imagePath);
paintImage(canvas: canvas, image: image, rect: oval, fit: BoxFit.fitWidth);
ui.Picture p = recorder.endRecording();
ByteData pngBytes = await (await p.toImage(300, 300))
.toByteData(format: ui.ImageByteFormat.png);
Uint8List data = Uint8List.view(pngBytes.buffer);
return BitmapDescriptor.fromBytes(data);
}
Future<ui.Image> getImageFromPath(String imagePath) async {
File imageFile = File(imagePath);
Uint8List imageBytes = imageFile.readAsBytesSync();
final Completer<ui.Image> completer = new Completer();
ui.decodeImageFromList(imageBytes, (ui.Image img) {
return completer.complete(img);
});
return completer.future;
}
Future<BitmapDescriptor> getMarkerIcon(String image, String name) async {
if (image != null) {
final File markerImageFile =
await DefaultCacheManager().getSingleFile(image);
Size s = Size(120, 120);
var icon = await createCustomMarkerBitmapWithNameAndImage(markerImageFile.path, s, name);
return icon;
} else {
return BitmapDescriptor.defaultMarker;
}
}
@override
void initState() {
super.initState();
setAllMarkers();
}
setAllMarkers() async {
markers.add(
Marker(
markerId: MarkerId("1"),
position: LatLng(30.699285146824476, 76.69179040341325),
icon: await getMarkerIcon(
"https://quizprojectapp.s3.us-east-2.amazonaws.com/quizImage_1629380529687.png",
"DAVID"),
),
);
markers.add(
Marker(
markerId: MarkerId("2"),
position: LatLng(30.70246327295858, 76.69501482303754),
icon: await getMarkerIcon(
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTcA3AmOb_BMAsPra4XquXuWFMNAi7grJL0ug&usqp=CAU",
"ROSE"),
),
);
markers.add(
Marker(
markerId: MarkerId("3"),
position: LatLng(30.704382049382055, 76.70102297115308),
icon: await getMarkerIcon(
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSuIavvjuQFB38Se2ZNa0GkZ1Gol3C5OwioHA&usqp=CAU",
"JASSABELLE"),
),
);
setState(() {});
}
@override
build(BuildContext context) {
return Scaffold(
body: GoogleMap(
initialCameraPosition:
CameraPosition(target: const LatLng(30.699285146824476, 76.69179040341325), zoom: 15),
markers: markers),
);
}
}
结果:
我刚刚发布了一篇文章,您可以在此处找到有关如何使用任何小部件自定义标记图标的文章。