如何使用 SwiftUI 获取当前位置?

Posted

技术标签:

【中文标题】如何使用 SwiftUI 获取当前位置?【英文标题】:How to get Current Location with SwiftUI? 【发布时间】:2019-06-10 20:22:20 【问题描述】:

尝试使用 swiftUI 获取当前位置。下面的代码,无法使用 didUpdateLocations 委托进行初始化。

class GetLocation : BindableObject 
    var didChange = PassthroughSubject<GetLocation,Never>()

    var location : CLLocation 
        didSet 
            didChange.send(self)
        
    
    init() 

【问题讨论】:

为什么你不能在这个类中创建 CLLocationManager? 【参考方案1】:

以下代码有效(未准备好生产)。实现CLLocationManagerDelegate 工作正常,lastKnownLocation 会相应更新。

别忘了在Info.plist 中设置NSLocationWhenInUseUsageDescription

class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate 
    private let manager = CLLocationManager()
    var lastKnownLocation: CLLocation?

    func startUpdating() 
        manager.delegate = self
        manager.requestWhenInUseAuthorization()
        manager.startUpdatingLocation()
    

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) 
        print(locations)
        lastKnownLocation = locations.last
    

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) 
        if status == .authorizedWhenInUse 
            manager.startUpdatingLocation()
        
    

【讨论】:

对于遇到错误的任何人:使用未解析的标识符“PassthroughSubject”,请确保将“import Combine”添加到文件顶部。【参考方案2】:

我在https://github.com/himbeles/LocationProvider 上编写了一个带有使用说明的单文件 swift 包。它为 CLLocationManager 及其委托提供了一个ObservableObject-type 包装类。 有一个 @Published 属性 location 可以直接在 SwiftUI 中使用,还有一个名为 locationWillChangePassthroughSubject&lt;CLLocation, Never&gt; 可以通过 Combine 订阅。两者都会在CLLocationManager 的每个didUpdateLocations 事件上更新。

它还处理位置访问先前被拒绝的情况:默认行为是向用户显示在应用设置中启用访问的请求以及前往该位置的链接。

在 SwiftUI (> ios 14, > macOS 11) 中,使用 as

import SwiftUI
import LocationProvider

struct ContentView: View 
    @StateObject var locationProvider = LocationProvider()
    
    var body: some View 
        VStack
            Text("latitude \(locationProvider.location?.coordinate.latitude ?? 0)")
            Text("longitude \(locationProvider.location?.coordinate.longitude ?? 0)")
        
        .onAppear 
            do try locationProvider.start() 
            catch 
                print("No location access.")
                locationProvider.requestAuthorization()
            
        
    

【讨论】:

这在 iOS 14 上对我不起作用,应用程序因此错误而崩溃 => '无效参数不满足:!stayUp || CLClientIsBackgroundable(internal->fClient) @Ahmadreza 好像后台权限有问题?您是否按照包装的README.md 中的说明将Location 添加到UIBackgroundModes?我已经使用 Xcode 12 beta 6 设置了一个最小的工作 SwiftUI 示例,它在设备和模拟器中都按预期运行。见github.com/himbeles/LocationProviderExample @lsrggr,不,我没有,一定是这样,谢谢,但我还是使用“Paul Hutson”方法进行定位。【参考方案3】:

从 Xcode 11 beta 4 开始,您需要将 didChange 更改为 willChange

var willChange = PassthroughSubject<LocationManager, Never>()

var lastKnownLocation: CLLocation? 
    willSet 
        willChange.send(self)
    

【讨论】:

另外,在 Xcode11.1 上,您需要将 BindableObject 更改为 ObservableObject- 我还需要在 lastKnownLocation 声明前面加上 @Published (XCode 12.0)

以上是关于如何使用 SwiftUI 获取当前位置?的主要内容,如果未能解决你的问题,请参考以下文章

使用 SwiftUI 和 MapKit 检索用户当前位置

获取 SwiftUI 中 ScrollView 的当前位置?

点击按钮时SwiftUI获取用户的位置

SwiftUI脑洞大开打造实时显示当前值的Slider

获取 SwiftUI ScrollView 的当前滚动位置

SwiftUI - 如何获取新创建的按钮的确切中心坐标/位置