前语

SwiftUI 与 MapKit 的集成在本年发生了严重变化。在之前的 SwiftUI 版别中,咱们将 MKMapView 的基本功能封装到名为 Map 的 SwiftUI 视图中。走运的是,事情发生了变化,SwiftUI 引入了与 MapKit 集成的新 API。本篇文章咱们将学习如安在 SwiftUI 的最新版别中运用可用的新功能丰厚的 API 与 MapKit 集成。

正如我之前所说,在 SwiftUI 框架的前期版别中,咱们有一个 Map 视图,为咱们供给了 MapKit 的基本功能,该功能现在已被弃用。在面向较早 Apple 渠道版别的情况下,依然运用已弃用的 Map 视图是有意义的。

新 MapKit API 的引入

新的 MapKit API 引入了 MapContentBuilder 成果构建器,它看起来类似于 ViewBuilder,但是运用符合 MapContent 协议的类型。让咱们从运用 SwiftUI 中最新迭代中供给的新 MapKit API 集成的基本示例开始。

import MapKit
import SwiftUI
extension CLLocationCoordinate2D {
    static let newYork: Self = .init(
        latitude: 40.730610,
        longitude: -73.935242
    )
    static let seattle: Self = .init(
        latitude: 47.608013,
        longitude: -122.335167
    )
    static let sanFrancisco: Self = .init(
        latitude: 37.733795,
        longitude: -122.446747
    )
}
struct ContentView: View {
    var body: some View {
        Map {
            Annotation("Seattle", coordinate: .seattle) {
                Image(systemName: "mappin")
                    .foregroundStyle(.black)
                    .padding()
                    .background(.red)
                    .clipShape(Circle())
            }
            Marker(coordinate: .newYork) {
                Label("New York", systemImage: "mappin")
            }
            Marker("San Francisco", monogram: Text("SF"), coordinate: .sanFrancisco)
        }
    }
}

正如你在上面的示例中看到的,咱们经过运用 MapContentBuilder 闭包界说地图,并在其上放置内容。MapContentBuilder 类型与符合 MapContent 协议的任何类型一同运用。

在咱们的示例中,咱们运用了 Marker 和 Annotation 类型。Marker 是一个基本项,答应咱们在地图上放置预界说的标记。Annotation 类型更先进,将使咱们能够运用纬度和经度在地图上放置 SwiftUI 视图。

SwiftUI 为咱们供给了许多符合 MapContent 协议的类型。咱们已经运用了其间的两个:Marker 和 Annotation。其间许多包含 MapCircle、MapPolygon、MapPolyline、UserAnnotation 等。

struct ContentView: View {
    var body: some View {
        Map {
            Annotation("Seattle", coordinate: .seattle) {
                Image(systemName: "mappin")
                    .foregroundStyle(.black)
                    .padding()
                    .background(.red)
                    .clipShape(Circle())
            }
            Marker(coordinate: .newYork) {
                Label("New York", systemImage: "mappin")
            }
            UserAnnotation()
        }
    }
}

操控初始地图方位

你能够经过运用 Map 初始化器的另一个重载来操控地图的初始方位,该初始化器供给 initialPosition 参数。

struct ContentView: View {
    let initialPosition: MapCameraPosition = .userLocation(
        fallback: .camera(
            MapCamera(centerCoordinate: .newYork, distance: 0)
        )
    )
    var body: some View {
        Map(initialPosition: initialPosition) {
            Annotation("Seattle", coordinate: .seattle) {
                Image(systemName: "mappin")
                    .foregroundStyle(.black)
                    .padding()
                    .background(.red)
                    .clipShape(Circle())
            }
            Marker(coordinate: .newYork) {
                Label("New York", systemImage: "mappin")
            }
            Marker("San Francisco", monogram: Text("SF"), coordinate: .sanFrancisco)
        }
    }
}

initialPosition 参数接受 MapCameraPosition 类型的实例。MapCameraPosition 答应咱们以几种方法界说地图方位。它能够是咱们在示例中运用的用户方位,或许你能够运用 camera、region、rect 或 item 等静态函数将其指向地图上的任何区域。默认情况下,它运用 MapCameraPosition 类型的主动实例,该类型合适地图内容。

相机方位的双向绑定

每逢你需要对相机方位有稳定的操控时,你能够运用 Map 初始化器的另一个重载,答应你供给与地图相机方位的双向绑定。

struct ContentView: View {
    @State private var position: MapCameraPosition = .userLocation(
        fallback: .camera(
            MapCamera(centerCoordinate: .newYork, distance: 0)
        )
    )
    var body: some View {
        Map(position: $position) {
            // ...
        }
    }
}

SwiftUI 在用户拖动地图时更新方位绑定。它还在你以编程方法更新 position 特点时立即更新地图相机方位。

struct ContentView: View {
    @State private var position: MapCameraPosition = .userLocation(
        fallback: .camera(
            MapCamera(centerCoordinate: .newYork, distance: 0)
        )
    )
    var body: some View {
        Map(position: $position, interactionModes: .pitch) {
            // ...
        }
    }
}

经过运用 interactionModes 参数,你能够操控与地图答应的交互类型。MapInteractionModes 类型界说了一组交互,如平移、俯仰、旋转和缩放。默认情况下,它启用所有可用的交互类型。

总结

今天,咱们学习了在 SwiftUI 中集成 MapKit 的基础知识。在接下来的几周里,咱们将持续评论相机操作、地图控件和其他高档主题。希望你喜欢这篇文章。