在 Swift 5/Swiftui 中重构一个 MapView(没有 Coordinators / UIViewRepresentables)

Refactor a MapView in Swift 5/Swiftui (Without Coordinators / UIViewRepresentables)

我现在有我想要的行为,但我想重构这段代码。我想将所有地图逻辑从我的视图中移除。

在持有这张地图的视图中,我有以下内容:

import SwiftUI
import MapKit

struct PostActivityView: View {
    @EnvironmentObject var viewModel: ActivitiesViewModel
    @EnvironmentObject var user: UserViewModel
    
    @State var region: MKCoordinateRegion
    @Binding var parentsTab: Tab
    
    @State private var locations = [MKPointAnnotation]()
    @State private var userTracking = MapUserTrackingMode.follow
.
.
.
                ZStack{
                    Map(coordinateRegion: $region, interactionModes: [MapInteractionModes.all], showsUserLocation: true, userTrackingMode: $userTracking)
                        .frame( height: 386)
                        .frame(height: 256)
                        .cornerRadius(25.0)
                        .shadow(radius: 10.0, x: 20, y: 10)
                    Circle()
                        .fill(Color.blue)
                        .opacity(0.3)
                        .frame(width: 16, height: 16)
                    Circle()
                        .fill(Color.black)
                        .opacity(0.3)
                        .frame(width: 1, height: 1)
                    HStack {
                        Spacer()
                        VStack {
                        Spacer()
                        HStack(){
                            VStack(){
                                Button(action: {zoom()}) {Image(systemName: "location.circle.fill")
                                    .background(Color.blue.opacity(0.75))
                                    .foregroundColor(.white)
                                    .font(.title)
                                    .clipShape(Circle())
                                    .rotationEffect(.degrees(30))
                                }
                            }
                            VStack(){
                                Button(action: {saveCrosshairLocation()}) {
                                Image(systemName: "checkmark.circle.fill")
                                    .background(Color.blue.opacity(0.75))
                                    .foregroundColor(.white)
                                    .font(.title)
                                    .clipShape(Circle())
                                }
                            }}}
                        }
                    }

还有这两个函数:

func saveCrosshairLocation() {
            let newLocation = MKPointAnnotation()
            newLocation.coordinate = self.region.center
            self.locations.append(newLocation)
            let local: CLLocation = CLLocation(latitude: self.region.center.latitude , longitude: self.region.center.longitude)
            CLGeocoder().reverseGeocodeLocation(local) { (placemarks, error) in
                guard error == nil else {
                    print("ReverseGeocode Error: \(String(describing: error))")
                    return
                }
                if let firstPlacemark = placemarks?.first {
                    print(firstPlacemark)
                    var addressString : String = ""
                    if firstPlacemark.name != nil {
                        addressString = addressString + firstPlacemark.name! + ", "
                    }else {
                        if firstPlacemark.subThoroughfare != nil {
                            addressString = addressString + firstPlacemark.subThoroughfare! + ", "
                        }
                        if firstPlacemark.thoroughfare != nil {
                            addressString = addressString + firstPlacemark.thoroughfare! + ", "
                        }
                    }
                    if firstPlacemark.subLocality != nil {
                        addressString = addressString + firstPlacemark.subLocality! + ", "
                    }
                    if firstPlacemark.locality != nil {
                        addressString = addressString + firstPlacemark.locality! + ", "
                    }
                    if firstPlacemark.country != nil {
                        addressString = addressString + firstPlacemark.country! + ", "
                    }
                    if firstPlacemark.postalCode != nil {
                        addressString = addressString + firstPlacemark.postalCode! + ", "
                    }
                    if firstPlacemark.region != nil {
                        addressString = addressString + "<\(local.coordinate.latitude),\(local.coordinate.longitude)>"
                    }
                    self.eventLocation = addressString
                }
            }
        }
    func zoom() {
        let newZoom = 0.08
        self.region = MKCoordinateRegion(center: user.getLocation(), span:  MKCoordinateSpan(latitudeDelta: newZoom, longitudeDelta: newZoom))
    }

我想将其重构为它自己的 CustomMapView.swift。我不确定 Map 是否与当前版本 swift 中的 MKMapView 相同。我不确定如何将它们绑定在一起。对于 customMapView,我希望有几个带有 @Binding 语法的变量,但同样,我在进行此重构时遇到了问题。

目标是让我成为更好的程序员,感谢您的帮助。

我主视图中的代码现在是:

Header:

struct PostActivityView: View {
    @EnvironmentObject var viewModel: ActivitiesViewModel
    @EnvironmentObject var user: UserViewModel
    
    @State var region: MKCoordinateRegion
    @Binding var parentsTab: Tab
    
    @State private var locations = [MKPointAnnotation]()
    @State private var userTracking = MapUserTrackingMode.follow
.
.
.

Body:

.
.
.
ForPlay_MapView(region: $region, userTracking: $userTracking, locations: $locations, eventLocation: $eventLocation)
.
.
.

地图视图现在是:

import SwiftUI
import MapKit

struct ForPlay_MapView : View {
    
    @EnvironmentObject var user: UserViewModel
    @Binding var region: MKCoordinateRegion
    @Binding var userTracking: MapUserTrackingMode
    @Binding var locations: [MKPointAnnotation]
    @Binding var eventLocation: String
    
    var body: some View {
        ZStack{
            Map(coordinateRegion: $region, interactionModes: [MapInteractionModes.all], showsUserLocation: true, userTrackingMode: $userTracking)
                .frame( height: 386)
                .frame(height: 256)
                .cornerRadius(25.0)
                .shadow(radius: 10.0, x: 20, y: 10)
            Circle()
                .fill(Color.blue)
                .opacity(0.3)
                .frame(width: 16, height: 16)
            Circle()
                .fill(Color.black)
                .opacity(0.3)
                .frame(width: 1, height: 1)
            HStack {
                Spacer()
                VStack {
                Spacer()
                HStack(){
                    VStack(){
                        Button(action: {zoom()}) {Image(systemName: "location.circle.fill")
                            .background(Color.blue.opacity(0.75))
                            .foregroundColor(.white)
                            .font(.title)
                            .clipShape(Circle())
                            .rotationEffect(.degrees(30))
                        }
                    }
                    VStack(){
                        Button(action: {saveCrosshairLocation()}) {
                        Image(systemName: "checkmark.circle.fill")
                            .background(Color.blue.opacity(0.75))
                            .foregroundColor(.white)
                            .font(.title)
                            .clipShape(Circle())
                        }
                    }}}
                }
            }
    }
    func saveCrosshairLocation() {
            let newLocation = MKPointAnnotation()
            newLocation.coordinate = self.region.center
            self.locations.append(newLocation)
            let local: CLLocation = CLLocation(latitude: self.region.center.latitude , longitude: self.region.center.longitude)
            CLGeocoder().reverseGeocodeLocation(local) { (placemarks, error) in
                guard error == nil else {
                    print("ReverseGeocode Error: \(String(describing: error))")
                    return
                }
                if let firstPlacemark = placemarks?.first {
                    print(firstPlacemark)
                    var addressString : String = ""
                    if firstPlacemark.name != nil {
                        addressString = addressString + firstPlacemark.name! + ", "
                    }else {
                        if firstPlacemark.subThoroughfare != nil {
                            addressString = addressString + firstPlacemark.subThoroughfare! + ", "
                        }
                        if firstPlacemark.thoroughfare != nil {
                            addressString = addressString + firstPlacemark.thoroughfare! + ", "
                        }
                    }
                    if firstPlacemark.subLocality != nil {
                        addressString = addressString + firstPlacemark.subLocality! + ", "
                    }
                    if firstPlacemark.locality != nil {
                        addressString = addressString + firstPlacemark.locality! + ", "
                    }
                    if firstPlacemark.country != nil {
                        addressString = addressString + firstPlacemark.country! + ", "
                    }
                    if firstPlacemark.postalCode != nil {
                        addressString = addressString + firstPlacemark.postalCode! + ", "
                    }
                    if firstPlacemark.region != nil {
                        addressString = addressString + "<\(local.coordinate.latitude),\(local.coordinate.longitude)>"
                    }
                    self.eventLocation = addressString
                }
            }
        }
    func zoom() {
        let newZoom = 0.08
        self.region = MKCoordinateRegion(center: user.getLocation(), span:  MKCoordinateSpan(latitudeDelta: newZoom, longitudeDelta: newZoom))
    }
}