MAUI Android自定义Map Pin上方绘制文本问题求助
问题:在MAUI地图Pin上方添加文本
我需要在地图Pin的上方绘制文本,尝试用Canvas绘制但未成功。现有代码如下,求解决方案。
当前效果

期望效果

现有代码
CustomMapHandler.cs
public class CustomMapHandler : MapHandler { public static readonly IPropertyMapper<IMap, IMapHandler> CustomMapper = new PropertyMapper<IMap, IMapHandler>(Mapper) { [nameof(IMap.Pins)] = MapPins, }; public CustomMapHandler() : base(CustomMapper, CommandMapper) { } public CustomMapHandler(IPropertyMapper? mapper = null, CommandMapper? commandMapper = null) : base( mapper ?? CustomMapper, commandMapper ?? CommandMapper) { } public List<Marker> Markers { get; } = new(); protected override void ConnectHandler(MapView platformView) { base.ConnectHandler(platformView); var mapReady = new MapCallbackHandler(this); PlatformView.GetMapAsync(mapReady); } private static new void MapPins(IMapHandler handler, IMap map) { if (handler is CustomMapHandler mapHandler) { mapHandler.Markers.Clear(); mapHandler.AddPins(map.Pins); } } private void AddPins(IEnumerable<IMapPin> mapPins) { if (Map is null || MauiContext is null) { return; } foreach (var pin in mapPins) { var pinHandler = pin.ToHandler(MauiContext); if (pinHandler is IMapPinHandler mapPinHandler) { var markerOption = mapPinHandler.PlatformView; if (pin is CustomPin cp) { cp.ImageSource.LoadImage(MauiContext, result => { if (result?.Value is BitmapDrawable bitmapDrawable) { markerOption.SetIcon(BitmapDescriptorFactory.FromBitmap(bitmapDrawable.Bitmap)); } AddMarker(Map, pin, Markers, markerOption); }); } else { AddMarker(Map, pin, Markers, markerOption); } } } } private static void AddMarker(GoogleMap map, IMapPin pin, List<Marker> markers, MarkerOptions markerOption) { var marker = map.AddMarker(markerOption); pin.MarkerId = marker.Id; markers.Add(marker); } }
MapCallbackHandler.cs
class MapCallbackHandler : Java.Lang.Object, IOnMapReadyCallback { private readonly IMapHandler mapHandler; public MapCallbackHandler(IMapHandler mapHandler) { this.mapHandler = mapHandler; } public void OnMapReady(GoogleMap googleMap) { mapHandler.UpdateValue(nameof(IMap.Pins)); } }
CustomPin.cs
public class CustomPin : Pin { public static readonly BindableProperty ImageSourceProperty = BindableProperty.Create(nameof(ImageSource), typeof(ImageSource), typeof(CustomPin)); public ImageSource? ImageSource { get => (ImageSource?)GetValue(ImageSourceProperty); set => SetValue(ImageSourceProperty, value); } }
MainPage.xaml.cs
void insertOnMap() { var customPinFromResource = new CustomPin() { Label = "From Resource", Location = new Location(48.95049, 2.62891), Address = "Address3", ImageSource = ImageSource.FromFile("map_large_vertical_stopped_marker.png"), Map = map }; map.Pins.Add(customPinFromResource); map.MoveToRegion(new MapSpan(new Location(48.95049, 2.62891), 48.95049, 2.62891)); }
MainPage.Xaml
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:maps="clr-namespace:Microsoft.Maui.Controls.Maps;assembly=Microsoft.Maui.Controls.Maps" xmlns:charts="clr-namespace:TestMap.Charts" x:Class="TestMap.MainPage"> <VerticalStackLayout> <Map x:Name="map" HeightRequest="400" MapType="Street" IsVisible="true"/> </VerticalStackLayout> </ContentPage>
解决方案
核心思路是将文本绘制到Pin的图标Bitmap上,合成新的Bitmap作为Marker的Icon,具体步骤如下:
1. 扩展CustomPin添加顶部文本属性
在CustomPin.cs中新增绑定属性,用于存储要显示在Pin上方的文本:
public class CustomPin : Pin { public static readonly BindableProperty ImageSourceProperty = BindableProperty.Create(nameof(ImageSource), typeof(ImageSource), typeof(CustomPin)); // 新增顶部文本属性 public static readonly BindableProperty TopTextProperty = BindableProperty.Create(nameof(TopText), typeof(string), typeof(CustomPin)); public ImageSource? ImageSource { get => (ImageSource?)GetValue(ImageSourceProperty); set => SetValue(ImageSourceProperty, value); } public string? TopText { get => (string?)GetValue(TopTextProperty); set => SetValue(TopTextProperty, value); } }
2. 添加文本绘制与图片合成方法
在CustomMapHandler.cs中新增方法,将文本绘制到原Pin图标的上方,合成新的Bitmap:
private Bitmap DrawTextOnTopOfPin(Bitmap originalBitmap, string text) { // 可根据需求调整字体、间距、颜色等参数 int textSize = 40; int padding = 8; // 计算合成后图片的宽高:取文本宽度和原图宽度的最大值,高度为文本+间距+原图高度 int totalWidth = Math.Max(originalBitmap.Width, (int)new Paint().MeasureText(text) + 10); int totalHeight = originalBitmap.Height + textSize + padding; // 创建空白Bitmap用于绘制 Bitmap combinedBitmap = Bitmap.CreateBitmap(totalWidth, totalHeight, Bitmap.Config.Argb8888); Canvas canvas = new Canvas(combinedBitmap); // 配置文本画笔 Paint textPaint = new Paint(); textPaint.Color = Android.Graphics.Color.Black; textPaint.TextSize = textSize; textPaint.TextAlign = Paint.Align.Center; textPaint.FakeBoldText = true; // 绘制文本到顶部居中位置 float textX = totalWidth / 2f; float textY = textSize - textPaint.Descent(); canvas.DrawText(text, textX, textY, textPaint); // 绘制原图标到文本下方居中位置 float iconX = (totalWidth - originalBitmap.Width) / 2f; float iconY = textSize + padding; canvas.DrawBitmap(originalBitmap, iconX, iconY, null); return combinedBitmap; }
3. 修改Pin加载逻辑,应用合成图片
修改CustomMapHandler.cs中AddPins方法里的图片加载逻辑,当存在顶部文本时使用合成后的图片:
cp.ImageSource.LoadImage(MauiContext, result => { if (result?.Value is BitmapDrawable bitmapDrawable) { Bitmap finalBitmap = bitmapDrawable.Bitmap; // 如果设置了顶部文本,合成新图片 if (!string.IsNullOrEmpty(cp.TopText)) { finalBitmap = DrawTextOnTopOfPin(finalBitmap, cp.TopText); } markerOption.SetIcon(BitmapDescriptorFactory.FromBitmap(finalBitmap)); } AddMarker(Map, pin, Markers, markerOption); });
4. 设置Pin的顶部文本
在MainPage.xaml.cs的insertOnMap方法中,给CustomPin添加TopText值:
var customPinFromResource = new CustomPin() { Label = "From Resource", TopText = "123", // 设置要显示在Pin上方的文本 Location = new Location(48.95049, 2.62891), Address = "Address3", ImageSource = ImageSource.FromFile("map_large_vertical_stopped_marker.png"), Map = map };
内容的提问来源于stack exchange,提问作者Frederico Nicola
相关产品推荐
相关产品推荐

