地图
.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 中设置所需的位置服务请求。 它们通常为以下一个或多个:
NSLocationAlwaysAndWhenInUseUsageDescription
– 用于随时使用位置服务。NSLocationWhenInUseUsageDescription
– 用于在使用应用时使用位置服务。
有关详细信息,请参阅 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>
然后,会在应用尝试访问用户的位置时显示请求访问的提示:
Android
在 Android 上显示地图并与之交互的配置过程是为了:
- 获取 Google Maps API 密钥并将其添加至应用清单。
- 在清单中指定 Google Play 服务版本号。
- [可选]在清单中指定位置权限。
- [可选]在清单中指定 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_LOCATION
或 ACCESS_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 或移动数据确定尽可能精确的位置。
然后,会在应用尝试访问用户的位置时显示请求访问的提示:
或者,可以在 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,指定在运行时将用于为图钉选择 DataTemplate 的 DataTemplateSelector。IsScrollEnabled
,类型为bool
,确定是否允许地图滚动。IsTrafficEnabled
,类型为bool
,指示地图上是否覆盖流量数据。IsZoomEnabled
,类型为bool
,确定是否允许地图缩放。MapElements
,类型为IList<MapElement>
,表示地图上的元素列表,如多边形和折线。MapType
,类型为MapType
,指示地图的显示样式。Pins
,类型为IList<Pin>
,表示地图上的图钉列表。VisibleRegion
,类型为MapSpan
,返回地图当前显示的区域。
这些属性中除 MapElements
、Pins
和 VisibleRegion
外,其他均由 BindableProperty 对象提供支持,这意味着它们可以成为数据绑定的目标。
Map 类还定义点击地图时触发的 MapClicked
事件。 事件附带的 MapClickedEventArgs
对象包含一个名为 Location
的属性,类型为 Location
。 触发此事件时,Location
属性将设置为点击的地图位置。 有关 Location
类的信息,请参阅位置和距离。
有关 ItemsSource
、ItemTemplate
和 ItemTemplateSelector
属性的信息,请参阅显示图钉集合。
显示地图
可以通过将 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.Map 和 Microsoft.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
对象:
ClampLatitude
返回与方法的类实例相同LongitudeDegrees
的MapSpan
,以及由其north
和south
参数定义的半径。FromCenterAndRadius
返回由其Location
和Distance
参数定义的MapSpan
。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 类定义类型为 bool
的 IsTrafficEnabled
属性。 默认情况下,此属性为 false
,指示不会在地图上覆盖流量数据。 将此属性设置为 true
时,将在地图上覆盖流量数据:
<maps:Map IsTrafficEnabled="true" />
等效 C# 代码如下:
Map map = new Map
{
IsTrafficEnabled = true
};
禁用滚动
Map 类定义类型为 bool
的 IsScrollEnabled
属性。 默认情况下,此属性为 true
,指示允许地图滚动。 将此属性设置为 false
时,地图将不会滚动:
<maps:Map IsScrollEnabled="false" />
等效 C# 代码如下:
Map map = new Map
{
IsScrollEnabled = false
};
禁用缩放
Map 类定义类型为 bool
的 IsZoomEnabled
属性。 默认情况下,此属性为 true
,指示可以在地图上执行缩放。 将此属性设置为 false
时,无法缩放地图:
<maps:Map IsZoomEnabled="false" />
等效 C# 代码如下:
Map map = new Map
{
IsZoomEnabled = false
};
显示用户位置
Map 类定义类型为 bool
的 IsShowingUser
属性。 默认情况下,此属性为 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);
或者,可以使用 FromKilometers
、FromMeters
、FromMiles
和 BetweenPositions
工厂方法创建 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
类还定义 MarkerClicked
和 InfoWindowClicked
事件。 点击图钉时会触发 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 类定义以下可绑定属性:
ItemsSource
,类型为IEnumerable
,指定要显示的IEnumerable
固定项的集合。ItemTemplate
,类型为 DataTemplate,指定要应用于所显示图钉集合中每个项的 DataTemplate。ItemTemplateSelector
,类型为 DataTemplateSelector,指定在运行时将用于为图钉选择 DataTemplate 的 DataTemplateSelector。
重要说明
同时设置 ItemTemplate
和 ItemTemplateSelector
属性时,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
对象都定义类型为 string
的 Address
和 Description
属性,以及类型为 Location
的 Location
属性。
可以定义 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
类定义 DefaultTemplate
和 SanFranTemplate
DataTemplate 属性,这些属性设置为不同的数据模板。 OnSelectTemplate
方法返回 SanFranTemplate
,点击 Pin
时,后者将“Xamarin”显示为标签,此时项的地址包含“San Francisco”。 如果项的地址不包含“San Francisco”,OnSelectTemplate
方法将返回 DefaultTemplate
。
注意
此功能的用例是基于 Pin
子类型将子类化 Pin
对象的属性绑定到不同的属性。
要详细了解数据模板选择器,请参阅创建 DataTemplateSelector。
多边形、折线和圆
Polygon
、Polyline
和 Circle
元素支持突出显示地图上的特定区域。 Polygon
是可以包含描边和填充颜色的完全闭合形状。 Polyline
是一条未完全封闭某区域的线条。 Circle
突出显示地图的圆形区域:
Polygon
、Polyline
和 Circle
类派生自 MapElement
类,该类公开以下可绑定属性:
StrokeColor
是确定线条颜色的 Color 对象。StrokeWidth
是确定线条宽度的float
对象。
Polygon
类定义其他可绑定属性:
FillColor
是确定多边形背景色的 Color 对象。
此外,Polygon
和 Polyline
类都定义 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);
指定 StrokeColor
和 StrokeWidth
属性以设置多边形的轮廓。 在此示例中,FillColor
属性值与 StrokeColor
属性值匹配,但指定了一个 alpha 值以使其透明,从而允许通过形状显示基础地图。 GeoPath
属性包含 Location
对象的列表,该对象定义多边形点的地理坐标。 将 Polygon
对象添加到 Map 的 MapElements
集合后,它将呈现在地图上。
注意
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);
指定 StrokeColor
和 StrokeWidth
属性以设置线条外观。 GeoPath
属性包含 Location
对象的列表,该对象定义折线点的地理坐标。 将 Polyline
对象添加到 Map 的 MapElements
集合后,该对象将呈现在地图上。
创建圆
可以通过实例化 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
在地图上的位置由 Center
和 Radius
属性的值确定。 Center
属性定义圆心(以纬度和经度表示),而 Radius
属性以米为单位定义圆的半径。 指定 StrokeColor
和 StrokeWidth
属性以设置圆的轮廓。 FillColor
属性值指定圆周内的颜色。 在此示例中,这两个颜色值都指定 alpha 通道,从而允许通过圆显示基础地图。 将 Circle
对象添加到 Map 的 MapElements
集合后,该对象将呈现在地图上。
注意
GeographyUtils
类包含 ToCircumferencePositions
扩展方法,该方法将 Circle
对象(定义 Center
和 Radius
属性值)转换为构成圆周的纬度和经度坐标的 Location
对象列表。
地理编码和地理位置
Microsoft.Maui.Devices.Sensors
命名空间中的 Geocoding
类可用于将地标地理编码为位置坐标,并将坐标反向地理编码为地标。 有关详细信息,请参阅地理编码。
Microsoft.Maui.Devices.Sensors
命名空间中的 Geolocation
类可用于检索设备的当前地理位置坐标。 有关详细信息,请参阅地理位置。
启动本机地图应用
每个平台上的本机地图应用都可以由 Launcher
类从 .NET MAUI 应用启动。 此类使应用能够通过其自定义 URI 方案打开另一个应用。 可以使用 OpenAsync
方法调用启动器功能,传入表示要打开的自定义 URL 方案的 string
或 Uri
参数。 要详细了解 Launcher
类,请参阅启动器。
每个平台上的地图应用都使用唯一的自定义 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");
}
此示例代码使本机地图应用可在每个平台上启动,其中地图以指定位置之间的路线为中心。