地图

浏览示例。浏览示例

.NET Multi-platform App UI (.NET MAUI) Map 控件是用于显示和批注地图的跨平台视图。 Map 控件在每个平台上使用本机地图控件,并由 Microsoft.Maui.Controls.Maps NuGet 包提供。

重要说明

由于 WinUI 中缺少地图控件,因此 Windows 不支持 Map 控件。 但是,CommunityToolkit.Maui.Maps NuGet 包通过 Windows 上的 WebView 提供对必应地图的访问权限。 有关详细信息,请参阅入门

设置

Map 控件在每个平台上使用本机地图控件。 这为用户提供快速、熟悉的地图体验,但意味着需要执行一些配置步骤遵守每个平台 API 要求。

地图初始化

Map 控件由 Microsoft.Maui.Controls.Maps NuGet 包提供,应将其添加到 .NET MAUI 应用项目中。

安装 NuGet 包后,必须在应用中通过对 MauiProgram 类的 CreateMauiApp 方法中的 MauiAppBuilder 对象调用 UseMauiMap 方法初始化该包:

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
            })
            .UseMauiMaps();

        return builder.Build();
    }
}

添加和初始化 NuGet 包后,即可在项目中使用 Map API。

平台配置

在显示地图之前,需要在 Android 上进行其他配置。 此外,在 iOS、Android 和 Mac Catalyst 上,访问用户的位置需要向应用授予位置权限。

iOS 和 Mac Catalyst

在 iOS 和 Mac Catalyst 上显示地图并与之交互不需要任何其他配置。 但是,要访问位置服务,应在 Info.plist 中设置所需的位置服务请求。 它们通常为以下一个或多个:

有关详细信息,请参阅 developer.apple.com 上的选择要请求的位置服务授权

Info.plist 中这些密钥的 XML 表示形式如下所示。 应更新 string 值以反映应用如何使用位置信息:

<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Can we use your location at all times?</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Can we use your location when your app is being used?</string>

然后,会在应用尝试访问用户的位置时显示请求访问的提示:

iOS 上的位置权限请求的屏幕截图。

Android

在 Android 上显示地图并与之交互的配置过程是为了:

  1. 获取 Google Maps API 密钥并将其添加至应用清单。
  2. 在清单中指定 Google Play 服务版本号。
  3. [可选]在清单中指定位置权限。
  4. [可选]在清单中指定 WRITE_EXTERNAL_STORAGE 权限。
获取 Google Maps API 密钥

要在 Android 上使用 Map 控件,必须生成 API 密钥,该密钥将由 Map 控件在 Android 上依赖的 Google Maps SDK 使用。 为此,请按照 developers.google.com 上的在 Google Cloud Console 中设置使用 API 密钥中的说明进行操作。

获取 API 密钥后,必须将其添加到 Platforms/Android/AndroidManifest.xml 文件的 <application> 元素中,方法是将其指定为 com.google.android.geo.API_KEY 元数据的值:

<application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true">
  <meta-data android:name="com.google.android.geo.API_KEY" android:value="PASTE-YOUR-API-KEY-HERE" />
</application>

这会将 API 密钥嵌入清单中。 如果没有有效的 API 密钥,则 Map 控件将显示空白网格。

注意

com.google.android.geo.API_KEY 是 API 密钥的推荐元数据名称。 使用此名称的密钥可用于在 Android 上对多个基于 Google Maps 的 API 进行身份验证。 为了向后兼容,可以使用 com.google.android.maps.v2.API_KEY 元数据名称,但只允许对 Android 地图 API v2 进行身份验证。 应用只能指定其中一个 API 密钥元数据名称。

指定 Google Play 服务版本号

在 AndroidManifest.xml<application> 元素中添加以下声明:

<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />

这会将编译应用时使用的 Google Play 服务版本嵌入到清单中。

指定位置权限

如果应用需要访问用户的位置,则必须通过将 ACCESS_COARSE_LOCATIONACCESS_FINE_LOCATION 权限(或两者)作为 <manifest> 元素的子元素添加到清单请求权限:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
  ...
  <!-- Required to access the user's location -->
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
</manifest>

ACCESS_COARSE_LOCATION 权限允许 API 使用 WiFi 或移动数据(或两者)确定设备的位置。 ACCESS_FINE_LOCATION 权限允许 API 使用全球定位系统 (GPS)、WiFi 或移动数据确定尽可能精确的位置。

然后,会在应用尝试访问用户的位置时显示请求访问的提示:

Android 上位置权限请求的屏幕截图。

或者,可以在 Visual Studio 的 Android 清单编辑器中启用这些权限。

指定 WRITE_EXTERNAL_STORAGE 权限

如果应用面向 API 22 或更低版本,则必须将 WRITE_EXTERNAL_STORAGE 权限作为 <manifest> 元素的子元素添加到清单:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

如果应用面向 API 23 或更高版本,则不需要这样做。

地图控件

Map 类定义以下用于控制地图外观和行为的属性:

  • IsShowingUser,类型为 bool,指示地图是否显示用户的当前位置。
  • ItemsSource,类型为 IEnumerable,指定要显示的 IEnumerable 固定项的集合。
  • ItemTemplate,类型为 DataTemplate,指定要应用于所显示图钉集合中每个项的 DataTemplate
  • ItemTemplateSelector,类型为 DataTemplateSelector,指定在运行时将用于为图钉选择 DataTemplateDataTemplateSelector
  • IsScrollEnabled,类型为 bool,确定是否允许地图滚动。
  • IsTrafficEnabled,类型为 bool,指示地图上是否覆盖流量数据。
  • IsZoomEnabled,类型为 bool,确定是否允许地图缩放。
  • MapElements,类型为 IList<MapElement>,表示地图上的元素列表,如多边形和折线。
  • MapType,类型为 MapType,指示地图的显示样式。
  • Pins,类型为 IList<Pin>,表示地图上的图钉列表。
  • VisibleRegion,类型为 MapSpan,返回地图当前显示的区域。

这些属性中除 MapElementsPinsVisibleRegion 外,其他均由 BindableProperty 对象提供支持,这意味着它们可以成为数据绑定的目标。

Map 类还定义点击地图时触发的 MapClicked 事件。 事件附带的 MapClickedEventArgs 对象包含一个名为 Location 的属性,类型为 Location。 触发此事件时,Location 属性将设置为点击的地图位置。 有关 Location 类的信息,请参阅位置和距离

有关 ItemsSourceItemTemplateItemTemplateSelector 属性的信息,请参阅显示图钉集合

显示地图

可以通过将 Map 添加到布局或页面来显示它:

<ContentPage ...
             xmlns:maps="http://schemas.microsoft.com/dotnet/2021/maui/maps">
    <maps:Map x:Name="map" />
</ContentPage>

等效 C# 代码如下:

using Map = Microsoft.Maui.Controls.Maps.Map;

namespace WorkingWithMaps
{
    public class MapTypesPageCode : ContentPage
    {
        public MapTypesPageCode()
        {
            Map map = new Map();
            Content = map;
        }
    }
}

此示例调用默认 Map 构造函数,该构造函数将地图以夏威夷毛伊岛为中心:

具有默认位置的地图控件的屏幕截图。

或者,可以将 MapSpan 参数传递给 Map 构造函数,以在加载地图时设置地图的中心点和缩放级别。 有关详细信息,请参阅在地图上显示特定位置

重要说明

.NET MAUI 有两种 Map 类型 - Microsoft.Maui.Controls.Maps.MapMicrosoft.Maui.ApplicationModel.Map。 由于 Microsoft.Maui.ApplicationModel 命名空间是 .NET MAUI 的其中一个 global using 指令,因此在代码中使用 Microsoft.Maui.Controls.Maps.Map 控件时,必须完全限定 Map 用法或使用 using 别名

地图类型

可以将 Map.MapType 属性设置为 MapType 枚举成员,以定义地图的显示样式。 MapType 枚举定义以下成员:

  • Street 指定将显示街道地图。
  • Satellite 指定将显示包含卫星图像的地图。
  • Hybrid 指定将显示合并街道和卫星数据的地图。

默认情况下,如果未定义 MapType 属性,则 Map 将显示街道地图。 或者,可以将 MapType 属性设置为其中一个 MapType 枚举成员:

<maps:Map MapType="Satellite" />

等效 C# 代码如下:

Map map = new Map
{
    MapType = MapType.Satellite
};

在地图上显示特定位置

可以通过将 MapSpan 参数传递给 Map 构造函数来设置加载地图时要显示的地图区域:

<ContentPage ...
             xmlns:maps="http://schemas.microsoft.com/dotnet/2021/maui/maps"
             xmlns:sensors="clr-namespace:Microsoft.Maui.Devices.Sensors;assembly=Microsoft.Maui.Essentials">
    <maps:Map>
        <x:Arguments>
            <maps:MapSpan>
                <x:Arguments>
                    <sensors:Location>
                        <x:Arguments>
                            <x:Double>36.9628066</x:Double>
                            <x:Double>-122.0194722</x:Double>
                        </x:Arguments>
                    </sensors:Location>
                    <x:Double>0.01</x:Double>
                    <x:Double>0.01</x:Double>
                </x:Arguments>
            </maps:MapSpan>
        </x:Arguments>
    </maps:Map>
</ContentPage>

等效 C# 代码如下:

using Microsoft.Maui.Maps;
using Map = Microsoft.Maui.Controls.Maps.Map;
...

Location location = new Location(36.9628066, -122.0194722);
MapSpan mapSpan = new MapSpan(location, 0.01, 0.01);
Map map = new Map(mapSpan);

此示例创建一个 Map 对象,该对象显示由 MapSpan 对象指定的区域。 MapSpan 对象以 Location 对象表示的经纬度为中心,跨越范围为纬度 0.01 度,经度 0.01 度。 有关 Location 类的信息,请参阅位置和距离。 有关在 XAML 中传递参数的信息,请参阅在 XAML 中传递参数

结果是,当显示地图时,它以特定位置为中心,并跨越特定数量的纬度和经度:

具有指定位置的地图控件的屏幕截图。

创建 MapSpan 对象

有多种方法可用于创建 MapSpan 对象。 一种常见的方法是向 MapSpan 构造函数提供所需的参数。 它们是由 Location 对象表示的经纬度,以及表示 MapSpan 跨越的经纬度的 double 值。 有关 Location 类的信息,请参阅位置和距离

或者,MapSpan 类中有三个方法可用于返回新的 MapSpan 对象:

  1. ClampLatitude 返回与方法的类实例相同 LongitudeDegreesMapSpan,以及由其 northsouth 参数定义的半径。
  2. FromCenterAndRadius 返回由其 LocationDistance 参数定义的 MapSpan
  3. WithZoom 返回一个 MapSpan,其中心点与方法的类实例相同,但具有乘以其 double 参数的半径。

有关 Distance 结构的信息,请参阅位置和距离

创建 MapSpan 后,可以访问以下属性来检索有关它的数据:

  • Center,类型为 Location,表示 MapSpan 地理中心的位置。
  • LatitudeDegrees,类型为 double,表示 MapSpan 所跨越的纬度。
  • LongitudeDegrees,类型为 double,表示 MapSpan 跨越的经度。
  • Radius,类型为 Distance,表示 MapSpan 半径。

移动地图

可以调用 Map.MoveToRegion 方法来更改地图的位置和缩放级别。 此方法接受 MapSpan 参数,该参数定义要显示的地图区域及其缩放级别。

以下代码显示了在地图上移动所显示区域的示例:

using Microsoft.Maui.Maps;
using Microsoft.Maui.Controls.Maps.Map;
...

MapSpan mapSpan = MapSpan.FromCenterAndRadius(location, Distance.FromKilometers(0.444));
map.MoveToRegion(mapSpan);

缩放地图

可以在不更改 Map 位置的情况下更改其缩放级别。 这可以通过地图 UI 完成,也可以通过调用包含 MapSpan 参数的 MoveToRegion 方法以编程方式完成,该参数将当前位置用作 Location 参数:

double zoomLevel = 0.5;
double latlongDegrees = 360 / (Math.Pow(2, zoomLevel));
if (map.VisibleRegion != null)
{
    map.MoveToRegion(new MapSpan(map.VisibleRegion.Center, latlongDegrees, latlongDegrees));
}

在此示例中,使用 MapSpan 参数调用 MoveToRegion 方法,该参数通过 Map.VisibleRegion 属性指定地图的当前位置,并将缩放级别指定为纬度数和经度数。 总体结果是地图的缩放级别已更改,但其位置未更改。 在地图上实现缩放的另一种方法是使用 MapSpan.WithZoom 方法控制缩放因子。

重要说明

缩放地图(无论通过地图 UI 还是以编程方式)都需要 Map.IsZoomEnabled 属性为 true。 要详细了解此属性,请参阅禁用缩放

自定义地图行为

可以通过设置 Map 的某些属性和处理 MapClicked 事件来自定义其行为。

注意

可以通过自定义其处理程序来自定义其他地图行为。 有关详细信息,请参阅使用处理程序自定义控件

显示交通情况数据

Map 类定义类型为 boolIsTrafficEnabled 属性。 默认情况下,此属性为 false,指示不会在地图上覆盖流量数据。 将此属性设置为 true 时,将在地图上覆盖流量数据:

<maps:Map IsTrafficEnabled="true" />

等效 C# 代码如下:

Map map = new Map
{
    IsTrafficEnabled = true
};

禁用滚动

Map 类定义类型为 boolIsScrollEnabled 属性。 默认情况下,此属性为 true,指示允许地图滚动。 将此属性设置为 false 时,地图将不会滚动:

<maps:Map IsScrollEnabled="false" />

等效 C# 代码如下:

Map map = new Map
{
    IsScrollEnabled = false
};

禁用缩放

Map 类定义类型为 boolIsZoomEnabled 属性。 默认情况下,此属性为 true,指示可以在地图上执行缩放。 将此属性设置为 false 时,无法缩放地图:

<maps:Map IsZoomEnabled="false" />

等效 C# 代码如下:

Map map = new Map
{
    IsZoomEnabled = false
};

显示用户位置

Map 类定义类型为 boolIsShowingUser 属性。 默认情况下,此属性为 false,指示地图未显示用户的当前位置。 将此属性设置为 true 时,地图显示用户的当前位置:

<maps:Map IsShowingUser="true" />

等效 C# 代码如下:

Map map = new Map
{
    IsShowingUser = true
};

重要说明

访问用户的位置需要向应用程序授予位置权限。 有关详细信息,请参阅平台配置

地图单击数

Map 类定义在点击地图时触发的 MapClicked 事件。 事件附带的 MapClickedEventArgs 对象包含一个名为 Location 的属性,类型为 Location。 触发此事件时,Location 属性将设置为点击的地图位置。 有关 Location 类的信息,请参阅位置和距离

以下代码示例显示 MapClicked 事件的事件处理程序:

void OnMapClicked(object sender, MapClickedEventArgs e)
{
    System.Diagnostics.Debug.WriteLine($"MapClick: {e.Location.Latitude}, {e.Location.Longitude}");
}

在此示例中,OnMapClicked 事件处理程序输出表示点击地图位置的纬度和经度。 必须向 MapClicked 事件注册该事件处理程序:

<maps:Map MapClicked="OnMapClicked" />

等效 C# 代码如下:

Map map = new Map();
map.MapClicked += OnMapClicked;

位置和距离

Microsoft.Maui.Devices.Sensors 命名空间包含通常在定位地图及其图钉时使用的 Location 类。 Microsoft.Maui.Maps 命名空间包含可以选择在定位地图时使用的 Distance 结构。

位置

Location 类封装存储为纬度和经度值的位置。 此类定义了以下属性:

  • Accuracy,类型为 double?,表示 Location 的水平精度(以米为单位)。
  • Altitude,类型为 double?,表示参照系中 AltitudeReferenceSystem 属性指定的海拔高度(以米为单位)。
  • AltitudeReferenceSystem,类型为 AltitudeReferenceSystem,指定提供海拔高度值的参照系。
  • Course,类型为 double?,指示相对于真北的度数值。
  • IsFromMockProvider,类型为 bool,指示位置是来源于 GPS 还是模拟位置提供程序。
  • Latitude,类型为 double,表示以十进制度数表示位置的纬度。
  • Longitude,类型为 double,表示以十进制度数表示位置的经度。
  • Speed,类型为 double?,表示每秒的速度(以米为单位)。
  • Timestamp,类型为 DateTimeOffset,表示创建 Location 时的时间戳。
  • VerticalAccuracy,类型为 double?,指定 Location 的垂直精度(以米为单位)。

Location 对象是使用其中一个 Location 构造函数重载创建的,这些重载通常至少需要将纬度和经度参数指定为 double 值:

Location location = new Location(36.9628066, -122.0194722);

创建 Location 对象时,纬度值将固定在 -90.0 和 90.0 之间,经度值将固定在 -180.0 和 180.0 之间。

注意

GeographyUtils 类包含将 double 值从度数转换为弧度的 ToRadians 扩展方法,以及将 double 值从弧度转换为度数的 ToDegrees 扩展方法。

Location 类还包含用于计算两个位置之间距离的 CalculateDistance 方法。

距离

Distance 结构封装存储为 double 值的距离,该值表示以米为单位的距离。 此结构定义三个只读属性:

  • Kilometers,类型为 double,表示 Distance 跨越的距离(以千米为单位)。
  • Meters,类型为 double,表示 Distance 跨越的距离(以米为单位)。
  • Miles,类型为 double,表示 Distance 跨越的距离(以英里为单位)。

可以使用 Distance 构造函数创建 Distance 对象,这需要指定为 double 的 meters 参数:

Distance distance = new Distance(1450.5);

或者,可以使用 FromKilometersFromMetersFromMilesBetweenPositions 工厂方法创建 Distance 对象:

Distance distance1 = Distance.FromKilometers(1.45); // argument represents the number of kilometers
Distance distance2 = Distance.FromMeters(1450.5);   // argument represents the number of meters
Distance distance3 = Distance.FromMiles(0.969);     // argument represents the number of miles
Distance distance4 = Distance.BetweenPositions(location1, location2);

Pin

Map 控件允许使用 Pin 对象标记位置。 Pin 是一个地图标记,在点击时打开信息窗口:

地图图钉及其信息窗口的屏幕截图。

Pin 对象添加到 Map.Pins 集合中时,将在地图上呈现图钉。

Pin 类具有以下属性:

  • Address,类型为 string,通常表示图钉位置的地址。 但是,它可以是任何 string 内容,而不仅仅是地址。
  • Label 的类型为 string,通常表示图钉标题。
  • Location 的类型为 Location,表示图钉的纬度和经度。
  • Type 的类型为 PinType,表示图钉的类型。

这些属性都由 BindableProperty 对象提供支持,这意味着 Pin 可以作为数据绑定的目标。 要详细了解数据绑定 Pin 对象,请参阅显示图钉集合

此外,Pin 类还定义 MarkerClickedInfoWindowClicked 事件。 点击图钉时会触发 MarkerClicked 事件,而点击信息窗口时会触发 InfoWindowClicked 事件。 两个事件随附的 PinClickedEventArgs 对象具有一个 HideInfoWindow 属性,类型为 bool

显示图钉

可以在 XAML 中将 Pin 添加到 Map

<ContentPage ...
             xmlns:maps="http://schemas.microsoft.com/dotnet/2021/maui/maps"
             xmlns:sensors="clr-namespace:Microsoft.Maui.Devices.Sensors;assembly=Microsoft.Maui.Essentials">
    <maps:Map x:Name="map">
        <x:Arguments>
            <maps:MapSpan>
                <x:Arguments>
                    <sensors:Location>
                        <x:Arguments>
                            <x:Double>36.9628066</x:Double>
                            <x:Double>-122.0194722</x:Double>
                        </x:Arguments>
                    </sensors:Location>
                    <x:Double>0.01</x:Double>
                    <x:Double>0.01</x:Double>
                </x:Arguments>
            </maps:MapSpan>
        </x:Arguments>
        <maps:Map.Pins>
            <maps:Pin Label="Santa Cruz"
                      Address="The city with a boardwalk"
                      Type="Place">
                <maps:Pin.Location>
                    <sensors:Location>
                        <x:Arguments>
                            <x:Double>36.9628066</x:Double>
                            <x:Double>-122.0194722</x:Double>
                        </x:Arguments>
                    </sensors:Location>
                </maps:Pin.Location>
            </maps:Pin>
        </maps:Map.Pins>
    </maps:Map>
</ContentPage>

此 XAML 会创建一个 Map 对象,该对象显示由 MapSpan 对象指定的区域。 MapSpan 对象以 Location 对象表示的经纬度为中心,该对象延伸 0.01 个经纬度值。 将 Pin 对象添加到 Map.Pins 集合中,并在 Map 上由其 Location 属性指定位置处绘制。 有关 Location 类的信息,请参阅位置和距离。 有关将 XAML 中的参数传递给缺少默认构造函数的对象的信息,请参阅在 XAML 中传递参数

等效 C# 代码如下:

using Microsoft.Maui.Controls.Maps;
using Microsoft.Maui.Maps;
using Map = Microsoft.Maui.Controls.Maps.Map;
...

Map map = new Map
{
  ...
};

Pin pin = new Pin
{
  Label = "Santa Cruz",
  Address = "The city with a boardwalk",
  Type = PinType.Place,
  Location = new Location(36.9628066, -122.0194722)
};
map.Pins.Add(pin);

此示例代码会生成在地图上呈现的单个图钉:

地图图钉的屏幕截图。

与图钉交互

默认情况下,点击 Pin 时,会显示其信息窗口:

地图图钉及其信息窗口的屏幕截图。

点击地图上的其他地方会关闭信息窗口。

Pin 类定义 MarkerClicked 事件,点击 Pin 时会触发该事件。 无需处理此事件即可显示信息窗口。 相反,当需要通知已点击特定图钉时,应处理此事件。

Pin 类还定义 InfoWindowClicked 事件,在点击信息窗口时会触发该事件。 当需要通知已点击特定信息窗口时,应处理此事件。

下方代码演示了处理这些事件的示例:

using Microsoft.Maui.Controls.Maps;
using Microsoft.Maui.Maps;
using Map = Microsoft.Maui.Controls.Maps.Map;
...

Pin boardwalkPin = new Pin
{
    Location = new Location(36.9641949, -122.0177232),
    Label = "Boardwalk",
    Address = "Santa Cruz",
    Type = PinType.Place
};
boardwalkPin.MarkerClicked += async (s, args) =>
{
    args.HideInfoWindow = true;
    string pinName = ((Pin)s).Label;
    await DisplayAlert("Pin Clicked", $"{pinName} was clicked.", "Ok");
};

Pin wharfPin = new Pin
{
    Location = new Location(36.9571571, -122.0173544),
    Label = "Wharf",
    Address = "Santa Cruz",
    Type = PinType.Place
};
wharfPin.InfoWindowClicked += async (s, args) =>
{
    string pinName = ((Pin)s).Label;
    await DisplayAlert("Info Window Clicked", $"The info window was clicked for {pinName}.", "Ok");
};

两个事件随附的 PinClickedEventArgs 对象具有一个 HideInfoWindow 属性,类型为 bool。 当此属性在事件处理程序中设置为 true 时,信息窗口将被隐藏。

图钉类型

Pin 对象包括 Type 属性,类型为 PinType,该属性表示图钉的类型。 PinType 枚举定义以下成员:

  • Generic,表示泛型图钉。
  • Place,表示位置的图钉。
  • SavedPin,表示已保存位置的图钉。
  • SearchResult,表示搜索结果的图钉。

但是,将 Pin.Type 属性设置为任何 PinType 成员均不会更改呈现图钉的外观。 相反,必须自定义 Pin 处理程序以自定义图钉外观。 要详细了解自定义处理程序,请参阅使用处理程序自定义控件

显示 Pin 集合

Map 类定义以下可绑定属性:

重要说明

同时设置 ItemTemplateItemTemplateSelector 属性时,ItemTemplate 属性将优先。

可以使用图钉填充 Map,方法是使用数据绑定将其 ItemsSource 属性绑定到 IEnumerable 集合:

<ContentPage ...
             xmlns:maps="http://schemas.microsoft.com/dotnet/2021/maui/maps">    
    <Grid>
        ...
        <maps:Map x:Name="map"
                  ItemsSource="{Binding Positions}">
            <maps:Map.ItemTemplate>
                <DataTemplate>
                    <maps:Pin Location="{Binding Location}"
                              Address="{Binding Address}"
                              Label="{Binding Description}" />
                </DataTemplate>    
            </maps:Map.ItemTemplate>
        </maps:Map>
        ...
    </Grid>
</ContentPage>

ItemsSource 属性数据绑定到连接视图模型的 Positions 属性,该属性返回 Position 对象的 ObservableCollection(一个自定义类型)。 每个 Position 对象都定义类型为 stringAddressDescription 属性,以及类型为 LocationLocation 属性。

可以定义 IEnumerable 集合中每个项的外观,方法是将 ItemTemplate 属性设置为包含数据绑定到相应属性的 Pin 对象的 DataTemplate

以下屏幕截图显示使用数据绑定显示 Pin 集合的 Map

包含数据绑定图钉的地图的屏幕截图。

在运行时选择项外观

可通过将 ItemTemplateSelector 属性设置为 DataTemplateSelector,在运行时根据项值选择 IEnumerable 集合中每个项的外观:

<ContentPage ...
             xmlns:templates="clr-namespace:WorkingWithMaps.Templates"
             xmlns:maps="http://schemas.microsoft.com/dotnet/2021/maui/maps">
    <ContentPage.Resources>
       <templates:MapItemTemplateSelector x:Key="MapItemTemplateSelector">
           <templates:MapItemTemplateSelector.DefaultTemplate>
               <DataTemplate>
                   <maps:Pin Location="{Binding Location}"
                             Address="{Binding Address}"
                             Label="{Binding Description}" />
               </DataTemplate>
           </templates:MapItemTemplateSelector.DefaultTemplate>
           <templates:MapItemTemplateSelector.SanFranTemplate>
               <DataTemplate>
                   <maps:Pin Location="{Binding Location}"
                             Address="{Binding Address}"
                             Label="Xamarin!" />
               </DataTemplate>
           </templates:MapItemTemplateSelector.SanFranTemplate>    
       </templates:MapItemTemplateSelector>
    </ContentPage.Resources>

    <Grid>
        ...
        <maps:Map x:Name="map"
                  ItemsSource="{Binding Positions}"
                  ItemTemplateSelector="{StaticResource MapItemTemplateSelector}">
        ...
    </Grid>
</ContentPage>

以下示例显示了 MapItemTemplateSelector 类:

using WorkingWithMaps.Models;

namespace WorkingWithMaps.Templates;

public class MapItemTemplateSelector : DataTemplateSelector
{
    public DataTemplate DefaultTemplate { get; set; }
    public DataTemplate SanFranTemplate { get; set; }

    protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
    {
        return ((Position)item).Address.Contains("San Francisco") ? SanFranTemplate : DefaultTemplate;
    }
}

MapItemTemplateSelector 类定义设置为不同数据模板的 DefaultTemplateSanFranTemplateDataTemplate 属性。 OnSelectTemplate 方法返回 SanFranTemplate,点击 Pin 时,后者将“Xamarin”显示为标签,此时项的地址包含“San Francisco”。 如果项的地址不包含“San Francisco”,OnSelectTemplate 方法将返回 DefaultTemplate

注意

此功能的用例是基于 Pin 子类型将子类化 Pin 对象的属性绑定到不同的属性。

要详细了解数据模板选择器,请参阅创建 DataTemplateSelector

多边形、折线和圆

PolygonPolylineCircle 元素支持突出显示地图上的特定区域。 Polygon 是可以包含描边和填充颜色的完全闭合形状。 Polyline 是一条未完全封闭某区域的线条。 Circle 突出显示地图的圆形区域:

地图上的多边形和折线。地图上的圆圈。

PolygonPolylineCircle 类派生自 MapElement 类,该类公开以下可绑定属性:

  • StrokeColor 是确定线条颜色的 Color 对象。
  • StrokeWidth 是确定线条宽度的 float 对象。

Polygon 类定义其他可绑定属性:

  • FillColor 是确定多边形背景色的 Color 对象。

此外,PolygonPolyline 类都定义 GeoPath 属性,该属性是指定形状点的 Location 对象的列表。

Circle 类定义以下可绑定属性:

  • Center 是定义圆心(以纬度和经度表示)的 Location 对象。
  • Radius 是定义圆半径(以米、千米或英里为单位)的 Distance 对象。
  • FillColor 是确定圆周内颜色的 Color 属性。

创建多边形

可以将 Polygon 对象添加到地图中,方法是实例化该对象并将其添加到地图的 MapElements 集合:

<ContentPage ...
             xmlns:maps="http://schemas.microsoft.com/dotnet/2021/maui/maps"
             xmlns:sensors="clr-namespace:Microsoft.Maui.Devices.Sensors;assembly=Microsoft.Maui.Essentials">
    <maps:Map>
        <maps:Map.MapElements>
            <maps:Polygon StrokeColor="#FF9900"
                          StrokeWidth="8"
                          FillColor="#88FF9900">
                <maps:Polygon.Geopath>
                    <sensors:Location>
                        <x:Arguments>
                            <x:Double>47.6458676</x:Double>
                            <x:Double>-122.1356007</x:Double>
                        </x:Arguments>
                    </sensors:Location>
                    <sensors:Location>
                        <x:Arguments>
                            <x:Double>47.6458097</x:Double>
                            <x:Double>-122.142789</x:Double>
                        </x:Arguments>
                    </sensors:Location>
                    ...
                </maps:Polygon.Geopath>
            </maps:Polygon>
        </maps:Map.MapElements>
    </maps:Map>
</ContentPage>

等效 C# 代码如下:

using Microsoft.Maui.Controls.Maps;
using Microsoft.Maui.Maps;
using Map = Microsoft.Maui.Controls.Maps.Map;
...

Map map = new Map();

// Instantiate a polygon
Polygon polygon = new Polygon
{
    StrokeWidth = 8,
    StrokeColor = Color.FromArgb("#1BA1E2"),
    FillColor = Color.FromArgb("#881BA1E2"),
    Geopath =
    {
        new Location(47.6368678, -122.137305),
        new Location(47.6368894, -122.134655),
        ...
    }
};

// Add the polygon to the map's MapElements collection
map.MapElements.Add(polygon);

指定 StrokeColorStrokeWidth 属性以设置多边形的轮廓。 在此示例中,FillColor 属性值与 StrokeColor 属性值匹配,但指定了一个 alpha 值以使其透明,从而允许通过形状显示基础地图。 GeoPath 属性包含 Location 对象的列表,该对象定义多边形点的地理坐标。 将 Polygon 对象添加到 MapMapElements 集合后,它将呈现在地图上。

注意

Polygon 是完全闭合的形状。 如果第一个点和最后一个点不匹配,它们将自动连接。

创建折线

可通过将 Polyline 对象实例化并添加到地图的 MapElements 集合来将该对象添加到地图中:

<ContentPage ...
             xmlns:maps="http://schemas.microsoft.com/dotnet/2021/maui/maps"
             xmlns:sensors="clr-namespace:Microsoft.Maui.Devices.Sensors;assembly=Microsoft.Maui.Essentials">
    <maps:Map>
        <maps:Map.MapElements>
            <maps:Polyline StrokeColor="Black"
                           StrokeWidth="12">
                <maps:Polyline.Geopath>
                    <sensors:Location>
                        <x:Arguments>
                            <x:Double>47.6381401</x:Double>
                            <x:Double>-122.1317367</x:Double>
                        </x:Arguments>
                    </sensors:Location>
                    <sensors:Location>
                        <x:Arguments>
                            <x:Double>47.6381473</x:Double>
                            <x:Double>-122.1350841</x:Double>
                        </x:Arguments>
                    </sensors:Location>
                    ...
                </maps:Polyline.Geopath>
            </maps:Polyline>
        </maps:Map.MapElements>
    </maps:Map>
</ContentPage>

等效 C# 代码如下:

using Microsoft.Maui.Controls.Maps;
using Microsoft.Maui.Maps;
using Map = Microsoft.Maui.Controls.Maps.Map;
...

Map map = new Map();

// instantiate a polyline
Polyline polyline = new Polyline
{
    StrokeColor = Colors.Blue,
    StrokeWidth = 12,
    Geopath =
    {
        new Location(47.6381401, -122.1317367),
        new Location(47.6381473, -122.1350841),
        ...
    }
};

// Add the Polyline to the map's MapElements collection
map.MapElements.Add(polyline);

指定 StrokeColorStrokeWidth 属性以设置线条外观。 GeoPath 属性包含 Location 对象的列表,该对象定义折线点的地理坐标。 将 Polyline 对象添加到 MapMapElements 集合后,该对象将呈现在地图上。

创建圆

可以通过实例化 Circle 对象并将其添加到地图的 MapElements 集合中来将其添加到地图中:

<ContentPage ...
             xmlns:maps="http://schemas.microsoft.com/dotnet/2021/maui/maps"
             xmlns:sensors="clr-namespace:Microsoft.Maui.Devices.Sensors;assembly=Microsoft.Maui.Essentials">
    <maps:Map>
        <maps:Map.MapElements>
            <maps:Circle StrokeColor="#88FF0000"
                         StrokeWidth="8"
                         FillColor="#88FFC0CB">
                <maps:Circle.Center>
                    <sensors:Location>
                        <x:Arguments>
                            <x:Double>37.79752</x:Double>
                            <x:Double>-122.40183</x:Double>
                        </x:Arguments>
                    </sensors:Location>
                </maps:Circle.Center>
                <maps:Circle.Radius>
                    <maps:Distance>
                        <x:Arguments>
                            <x:Double>250</x:Double>
                        </x:Arguments>
                    </maps:Distance>
                </maps:Circle.Radius>
            </maps:Circle>             
        </maps:Map.MapElements>
    </maps:Map>
</ContentPage>

等效 C# 代码如下:

using Microsoft.Maui.Controls.Maps;
using Microsoft.Maui.Maps;
using Map = Microsoft.Maui.Controls.Maps.Map;

Map map = new Map();

// Instantiate a Circle
Circle circle = new Circle
{
    Center = new Location(37.79752, -122.40183),
    Radius = new Distance(250),
    StrokeColor = Color.FromArgb("#88FF0000"),
    StrokeWidth = 8,
    FillColor = Color.FromArgb("#88FFC0CB")
};

// Add the Circle to the map's MapElements collection
map.MapElements.Add(circle);

Circle 在地图上的位置由 CenterRadius 属性的值确定。 Center 属性定义圆心(以纬度和经度表示),而 Radius 属性以米为单位定义圆的半径。 指定 StrokeColorStrokeWidth 属性以设置圆的轮廓。 FillColor 属性值指定圆周内的颜色。 在此示例中,这两个颜色值都指定 alpha 通道,从而允许通过圆显示基础地图。 将 Circle 对象添加到 MapMapElements 集合后,该对象将呈现在地图上。

注意

GeographyUtils 类包含 ToCircumferencePositions 扩展方法,该方法将 Circle 对象(定义 CenterRadius 属性值)转换为构成圆周的纬度和经度坐标的 Location 对象列表。

地理编码和地理位置

Microsoft.Maui.Devices.Sensors 命名空间中的 Geocoding 类可用于将地标地理编码为位置坐标,并将坐标反向地理编码为地标。 有关详细信息,请参阅地理编码

Microsoft.Maui.Devices.Sensors 命名空间中的 Geolocation 类可用于检索设备的当前地理位置坐标。 有关详细信息,请参阅地理位置

启动本机地图应用

每个平台上的本机地图应用都可以由 Launcher 类从 .NET MAUI 应用启动。 此类使应用能够通过其自定义 URI 方案打开另一个应用。 可以使用 OpenAsync 方法调用启动器功能,传入表示要打开的自定义 URL 方案的 stringUri 参数。 要详细了解 Launcher 类,请参阅启动器

注意

使用 Launcher 类的替代方法是使用 Microsoft.Maui.ApplicationModel 命名空间中的 Map 类。 有关详细信息,请参阅地图

每个平台上的地图应用都使用唯一的自定义 URI 方案。 有关 iOS 上的地图 URI 方案的信息,请参阅 developer.apple.com 上的地图链接。 有关 Android 上地图 URI 方案的信息,请参阅 developers.android.com 上的地图开发人员指南适用于 Android 的 Google 地图意向。 有关 Windows 上地图 URI 方案的信息,请参阅启动 Windows 地图应用

在特定位置启动地图应用

可以通过向每个地图应用的自定义 URI 方案添加适当的查询参数来打开本机地图应用中的位置:

if (DeviceInfo.Current.Platform == DevicePlatform.iOS || DeviceInfo.Current.Platform == DevicePlatform.MacCatalyst)
{
    // https://developer.apple.com/library/ios/featuredarticles/iPhoneURLScheme_Reference/MapLinks/MapLinks.html
    await Launcher.OpenAsync("http://maps.apple.com/?q=394+Pacific+Ave+San+Francisco+CA");
}
else if (DeviceInfo.Current.Platform == DevicePlatform.Android)
{
    // opens the Maps app directly
    await Launcher.OpenAsync("geo:0,0?q=394+Pacific+Ave+San+Francisco+CA");
}
else if (DeviceInfo.Current.Platform == DevicePlatform.WinUI)
{
    await Launcher.OpenAsync("bingmaps:?where=394 Pacific Ave San Francisco CA");
}

此示例代码使本机地图应用可在每个平台上启动,其中地图以表示特定位置的图钉为中心。

启动包含路线的地图应用

可以通过向每个地图应用的自定义 URI 方案添加适当的查询参数来启动显示路线的本机地图应用:

if (DeviceInfo.Current.Platform == DevicePlatform.iOS || DeviceInfo.Current.Platform == DevicePlatform.MacCatalyst)
{
    // https://developer.apple.com/library/ios/featuredarticles/iPhoneURLScheme_Reference/MapLinks/MapLinks.html
    await Launcher.OpenAsync("http://maps.apple.com/?daddr=San+Francisco,+CA&saddr=cupertino");
}
else if (DeviceInfo.Current.Platform == DevicePlatform.Android)
{
    // opens the 'task chooser' so the user can pick Maps, Chrome or other mapping app
    await Launcher.OpenAsync("http://maps.google.com/?daddr=San+Francisco,+CA&saddr=Mountain+View");
}
else if (DeviceInfo.Current.Platform == DevicePlatform.WinUI)
{
    await Launcher.OpenAsync("bingmaps:?rtp=adr.394 Pacific Ave San Francisco CA~adr.One Microsoft Way Redmond WA 98052");
}

此示例代码使本机地图应用可在每个平台上启动,其中地图以指定位置之间的路线为中心。