使用 Mapkit 的连续用户中心

continuous center of user with Mapkit

下午好,

我在显示地图时遇到问题,因为它只以用户为中心,并且会随着用户移动而停留在用户身上。我的错误出现在我标记 //HERE.

的视图文件中

我的错误是类型 '()' 不符合 'View'

  1. 为什么这一行给我一个错误?如果那行 运行s,我的假设是地图区域正在改变,但它仍然会 return 符合的地图。查看文件如下。

  2. 如果我 运行 它没有注释行,它不会显示我的当前位置。我将我的模拟器设置设置为功能 > 位置 > Apple。即使我正在缩小,地图上也没有任何标记。

    
            import SwiftUI
            import MapKit
    
            struct Location: Identifiable {
            let id = UUID()
    
            let name: String
            let content: String?
            let lat: Double
            let lon: Double
            var dangerLevel: CGFloat? = 10.0
            var coord: CLLocationCoordinate2D { CLLocationCoordinate2D(latitude: lat, longitude: lon) }
        }
    
        struct ContentView: View {
            @EnvironmentObject var locationManager: LocationManager
            @State private var userTrackingMode: MapUserTrackingMode = .follow
    
            @State var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 40.7128, longitude: 74.0060), span: MKCoordinateSpan( latitudeDelta: 0.03, longitudeDelta: 0.03))
    
            var body: some View {
                var locationManager = LocationManager()
                region = MKCoordinateRegion(center: locationManager.location!.coordinate, span: MKCoordinateSpan( latitudeDelta: 0.03, longitudeDelta: 0.03)) // HERE!!!!
    
    
    
                VStack {
                    Map(coordinateRegion: $region,
                        interactionModes: .all,
                        showsUserLocation: true)
    
                }
    
            }
        }
    
        struct ContentView_Previews: PreviewProvider {
            static var previews: some View {
                ContentView().environmentObject(LocationManager())
            }
        }
    
    
    
    

这是我定义 locationManager 的下一个文件

import Foundation
import CoreLocation

class LocationManager: NSObject, ObservableObject {
    private let locationManager = CLLocationManager()
    @Published var location: CLLocation?
    
    override init() {
        super.init()
        self.locationManager.delegate = self
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
        self.locationManager.requestWhenInUseAuthorization()
        self.locationManager.startUpdatingLocation()
    }
}
extension LocationManager : CLLocationManagerDelegate {
    func locationManager(_ manager: CLLocationManager,
                         didUpdateLocations locations: [CLLocation]) {
        guard let location = locations.last else { return }
        self.location = location
    }
    
    
}

您的代码存在一些问题。首先,要回答提出的问题,您应该避免将不是视图的变量直接放入 var body。虽然有办法绕过这个限制,但没有充分的理由再绕过。由于 region 不是视图,代码通过错误。是的,我知道您定义了 var locationManager 并且 ViewBuilder 将其视为变量的初始化,而不是变量本身。但是,您已经引用了在 header 中定义的 locationManager。用那个。

我对您的代码进行了一些更改,并添加了注释以帮助解决问题。如果您还有其他问题,请告诉我。

struct ContentView: View {
    // Unless you are using locationManager all over your code, you don't need to pass it as an
    // .environmentObject, though you can if needed. Since this is the first instance in this example
    // of locationManager, I made it a @StateObject.
    @StateObject var locationManager = LocationManager()
    @State private var userTrackingMode: MapUserTrackingMode = .follow
    @State var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 37.60697453, longitude: -122.42798519), span: MKCoordinateSpan( latitudeDelta: 0.03, longitudeDelta: 0.03))

    var body: some View {
        VStack {
            Map(coordinateRegion: $region,
                interactionModes: .all,
                showsUserLocation: true)
            // Since locationManager is an ObservableObject, you can watch for changes with .onChange(of:)
            .onChange(of: locationManager.location) { newLocation in
                // Never force unwrap an optional unless you just set it yourself in the code.
                guard let newLocation = newLocation else { return }
                region = MKCoordinateRegion(center: newLocation.coordinate, span: MKCoordinateSpan( latitudeDelta: 0.03, longitudeDelta: 0.03)) // HERE!!!!
            }
        }
        
    }
}

import CoreLocation

// I would consider renaming this class. It can be confusing to see
// locationManager.locationManager in code.
class LocationManager: NSObject, ObservableObject {
    private let locationManager = CLLocationManager()
    @Published var location: CLLocation?

    override init() {
        super.init()
        // You can generally drop .self, with some exceptions. The compiler will correct you.
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.requestWhenInUseAuthorization()
        locationManager.startUpdatingLocation()
    }
}

extension LocationManager : CLLocationManagerDelegate {
    func locationManager(_ manager: CLLocationManager,
                         didUpdateLocations locations: [CLLocation]) {
        guard let location = locations.last else { return }
        // This is an exception to dropping self when a variable in a closure has the same name as a
        // self variable.
        self.location = location
    }
}