在 SwiftUI 中实战使用 MapKit API

前言

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 集成的基本示例开始。

swift 复制代码
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 等。

swift 复制代码
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 参数。

swift 复制代码
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 初始化器的另一个重载,允许你提供与地图相机位置的双向绑定。

swift 复制代码
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 属性时立即更新地图相机位置。

swift 复制代码
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 的基础知识。在接下来的几周里,我们将继续讨论相机操作、地图控件和其他高级主题。希望你喜欢这篇文章。

相关推荐
阿里超级工程师12 小时前
最新快速申请ios打包证书和profile文件步骤
ios·打包证书
VIP_CQCRE14 小时前
用 Ace Data Cloud 快速接入 Suno 声音克隆 API:让 AI 音乐拥有专属声线
人工智能·ai·aigc·api·音乐生成
星核0penstarry15 小时前
从 Dialog-RSN-1 看语音 Agent 走向:企业如何评估音频原生模型与 API 服务
人工智能·音视频·音频·api
2501_9159090616 小时前
iOS 应用反调试技详解术 检测调试器的原理与防护实践
android·ios·小程序·https·uni-app·iphone·webview
游戏开发爱好者817 小时前
TraceEagle 代理抓包详解,无感代理、去证书绑定与 HTTP/3 解密能力解析
网络协议·计算机网络·网络安全·ios·adb·https·udp
aiopencode18 小时前
SwiftUI Introspect生产环境完全指南:为什么它是安全可靠的选择
后端·ios
for_ever_love__19 小时前
iOS: 网络管理单例
学习·ios·objective-c
gsls20080819 小时前
大模型供应商API端点兼容协议
大模型·api·协议·兼容
00后程序员张19 小时前
iOS加固技术路线全面解析:Bitcode模式、源码模式与汇编模式对比及爱加密优势
android·汇编·ios·小程序·uni-app·cocoa·iphone
VIP_CQCRE1 天前
用 Ace Data Cloud 接入 Suno 声音克隆 API:让 AI 音乐生成拥有专属人声
aigc·api·suno·ai音乐·ace data cloud