You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 8 MAUI中如何让谷歌地图Pin标签始终显示或添加底部文本?

问题

我开发了一个.NET 8 MAUI移动端项目,已经实现了地图功能,用图标代表被追踪的实体设备,要求所有图标都显示设备ID文本。但创建Pin时发现,Pin的Label属性只有选中该Pin时才会显示,未选中就隐藏,而且Pin类里没有能让标签一直显示的属性。

添加Pin的代码示例:

foreach (var element in CollectionsMarshal.AsSpan(AppShell.ListaUnidades))
{
    var temp = new CustomPin()
    {
        Label = element.idtra,
        Location = new Location(Convert.ToDouble(element.paclat), Convert.ToDouble(element.paclon)),
        ImageSource = ImageSource.FromFile(ObtenerRumbo(element.pacrum) + element.Icono),
    };
    MapaUnidades.Pins.Add(temp);
}

CustomPin类继承自Pin,新增了ImageSource属性用来自定义Pin图标。我试过通过CustomMapHandler修改markerOptions来让标签一直显示,但只能控制整个Pin的可见性,代码示例如下:

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 { Bitmap: not null } bitmapDrawable)
                {
                    markerOption.SetIcon(BitmapDescriptorFactory.FromBitmap(GetMaximumBitmap(bitmapDrawable.Bitmap, 100, 100)));
                }
                
                AddMarker(Map, pin, markerOption);
            });
            
        }
        else
        {
            AddMarker(Map, pin, markerOption);
        }
    }
}

请问有没有办法让Pin标签始终显示?或者能不能在Pin下方加个文本(哪怕不属于Pin的一部分也行)?

解决方案

Android平台

Android这边,你可以修改MarkerOptions的SetTitle和SetSnippet,设置InfoWindowAnchor,再强制让InfoWindow一直显示。更直接的办法是在创建Marker后调用ShowInfoWindow(),同时监听地图的CameraIdle事件,保证地图移动后重新显示InfoWindow:

在你的CustomMapHandler的AddMarker方法里,创建Marker后直接调用显示方法:

private Marker AddMarker(GoogleMap map, Pin pin, MarkerOptions markerOptions)
{
    var marker = map.AddMarker(markerOptions);
    // 强制显示InfoWindow
    marker.ShowInfoWindow();
    // 地图移动结束后重新显示,避免被隐藏
    map.CameraIdle += (s, e) => marker.ShowInfoWindow();
    return marker;
}

要是想让标签和图标更贴合,还可以自定义InfoWindow的布局,替换默认样式:

  1. 在Android项目的Resources/layout目录下创建custom_info_window.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:background="@android:color/transparent">

    <TextView
        android:id="@+id/info_window_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@android:color/black"
        android:textSize="12sp"
        android:layout_gravity="center_horizontal"/>
</LinearLayout>
  1. 在CustomMapHandler里设置自定义的InfoWindowAdapter:
map.SetInfoWindowAdapter(new CustomInfoWindowAdapter(MauiContext.Context));

// 自定义InfoWindowAdapter类
public class CustomInfoWindowAdapter : Java.Lang.Object, GoogleMap.IInfoWindowAdapter
{
    private readonly View _infoWindow;

    public CustomInfoWindowAdapter(Context context)
    {
        _infoWindow = LayoutInflater.From(context).Inflate(Resource.Layout.custom_info_window, null);
    }

    public View GetInfoContents(Marker marker)
    {
        var titleTextView = _infoWindow.FindViewById<TextView>(Resource.Id.info_window_title);
        titleTextView.Text = marker.Title;
        return _infoWindow;
    }

    public View GetInfoWindow(Marker marker)
    {
        return null; // 使用GetInfoContents返回的布局
    }
}

iOS平台

iOS上,MKMarkerAnnotationView默认只在选中时显示标题,要让标题一直显示,得自定义MKAnnotationView,把CanShowCallout设为true,再添加一个UILabel作为子视图放在图标下方:

在iOS项目的CustomMapHandler中处理AnnotationView时:

protected override MKAnnotationView CreateMarker(Pin pin)
{
    if (pin is CustomPin customPin)
    {
        var annotationView = new MKAnnotationView(customPin, "CustomPin");
        // 设置自定义图标
        if (customPin.ImageSource is FileImageSource fileSource)
        {
            annotationView.Image = UIImage.FromFile(fileSource.File);
        }
        // 添加标题标签
        var titleLabel = new UILabel
        {
            Text = customPin.Label,
            Font = UIFont.SystemFontOfSize(12),
            TextColor = UIColor.Black,
            BackgroundColor = UIColor.Clear,
            TextAlignment = UITextAlignment.Center,
            AutoresizingMask = UIViewAutoresizing.FlexibleWidth
        };
        // 把标签放在图标下方,调整位置
        titleLabel.Frame = new CGRect(0, annotationView.Image.Size.Height + 2, annotationView.Image.Size.Width, 20);
        annotationView.AddSubview(titleLabel);
        return annotationView;
    }
    return base.CreateMarker(pin);
}

这样标签会直接作为自定义AnnotationView的子视图,始终显示在图标下方,不用依赖Callout。

跨平台通用方案(自定义Overlay)

要是不想分平台折腾,也可以用地图的Overlay功能,在每个Pin的位置单独绘制文本:

  1. 先创建一个自定义的MapOverlay类,包含位置和文本信息:
public class TextOverlay : IOverlay
{
    public Location Location { get; set; }
    public string Text { get; set; }
}
  1. 在CustomMapHandler中,把这些TextOverlay转换成平台原生的Overlay:
  • Android:可以用GroundOverlay或者Canvas绘制文本
  • iOS:用MKOverlayRenderer绘制文本

这种方式的好处是文本完全独立于Pin,不受Pin的交互影响,一直显示。

内容的提问来源于stack exchange,提问作者Eli Sal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 16:47:09