Apple 提供了一个 SwiftUI Map视图,它精美地包装了底层地图框架,让我们可以将地图、注释等与 SwiftUI 视图层次结构的其余部分一起放置。 地图及其所有配置数据都来自一个名为 MapKit 的专用框架,
简单显示地图
可以调整用户使用地图的方式,例如他们是否可以缩放或旋转其位置。例如,我们可以制作一张始终保持以特定位置为中心的地图,但用户仍然可以调整旋转和缩放:
scss
Map(interactionModes: [.rotate, .zoom])
可以不指定交互模式,这意味着地图始终是完全固定的:
scss
Map(interactionModes: [ ])
使用mapStyle()修改器来控制地图的外观
- 卫星地图
- 将卫星地图和街道地图结合起来
- 可以获取两张地图以及真实的海拔高度,创建 3D 地图
这些都是简单的自定义选项,但其中三个需要更多思考:控制位置、放置注释和处理点击。
初始位置
创建一个存储伦敦位置的常量属性,跨度指定为 1 度 x 1 度:
less
let position = MapCameraPosition.region(
MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 51.507222, longitude: -0.1275),
span: MKCoordinateSpan(latitudeDelta: 1, longitudeDelta: 1)
)
)
初始化传入位置
scss
Map(initialPosition: position)
移动位置
如果您想随着时间的推移更改位置,则需要将其标记为@State然后将其作为绑定传递。
当position值发生变化,地图位置就会运动到该位置
跟踪位置变化
onMapCameraChange()修饰符,可以告诉我们位置何时发生变化,是立即发生变化还是在运动结束后发生变化。 可以编写当他们完成拖动地图时获取更新
scss
Map(position: $position)
.onMapCameraChange { context in
print(context.region)
}
也可以让它发布连续更新:
scss
Map(position: $position)
.onMapCameraChange(frequency: .continuous) { context in
print(context.region)
}
放置注释球 Maker
需要三个步骤:定义包含您的位置的新数据类型,创建包含您所有位置的数组,然后将它们添加为地图中的注释。无论您创建什么新数据类型来存储位置,它都必须符合Identifiable协议,以便 SwiftUI 可以唯一地识别每个地图标记。
swift
struct Location: Identifiable {
let id = UUID()
var name: String
var coordinate: CLLocationCoordinate2D
}
php
let locations = [
Location(name: "Buckingham Palace", coordinate: CLLocationCoordinate2D(latitude: 51.501, longitude: -0.141)),
Location(name: "Tower of London", coordinate: CLLocationCoordinate2D(latitude: 51.508, longitude: -0.076))
]
第三步是重要的部分:我们可以将该位置数组Map作为其内容输入到视图中。 SwiftUI 为我们提供了几种不同的内容类型,但一种简单的内容类型称为Marker:附有标题和纬度/经度坐标的气球。
scss
Map {
ForEach(locations) { location in
Marker(location.name, coordinate: location.coordinate)
}
}
自定义标记
如果您想更好地控制标记在地图上的显示方式,请使用Annotation。这使您可以提供完全自定义的视图,来代替标准系统标记气球 Maker,并且如果您愿意,您可以隐藏默认标题,以便您可以将其替换为您自己的标题,如下所示:
scss
Map {
ForEach(locations) { location in
Annotation(location.name, coordinate: location.coordinate) {
Text(location.name)
.font(.headline)
.padding()
.background(.blue)
.foregroundStyle(.white)
.clipShape(.capsule)
}
.annotationTitles(.hidden)
}
}
点击地图
最后,您可以使用onTapGesture()
处理地图上的点击。这告诉我们用户在地图上点击的位置,但它是在屏幕坐标中进行的- 例如,距顶部 50 点,距左侧 100 点。
为了获得地图上的实际位置,我们需要一个名为 MapReader 的特殊视图。当您将其中一个包裹在地图上时,您将收到一个特殊的MapProxy对象,该对象能够将屏幕位置转换为地图位置,并以另一种方式转换回来。
scss
MapReader { proxy in
Map()
.onTapGesture { position in
if let coordinate = proxy.convert(position, from: .local) {
print(coordinate)
}
}
}
.local
部分意味着我们正在转换地图本地坐标空间中的位置,这意味着我们正在使用的点击位置是相对于地图的左上角而不是整个屏幕或其他一些坐标空间。