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

Posted

技术标签:

【中文标题】在 Swift 5/Swiftui 中重构 MapView(没有 Coordinators / UIViewRepresentables)【英文标题】:Refactor a MapView in Swift 5/Swiftui (Without Coordinators / UIViewRepresentables) 【发布时间】:2021-07-03 17:47:54 【问题描述】:

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

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

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 语法的变量,但我在重构时遇到了麻烦。

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

【问题讨论】:

所以,我有这个 ZStack,它以我喜欢的方式显示地图,以及随之而来的两个功能。这些都在“PostView.Swift”中。我想把它拿出来,并用 CustomMapView($var1, $var2, $var3) 之类的东西替换它。用这种新的 swift 编写方式进行重构仍然有点超出我的技能水平。我希望有人向我展示重构它的正确方法。再说一次,基本上,我希望这张地图是一个组件,我可以只用一行插入。 此代码可能会有所帮助***.com/a/60460829/3891850 【参考方案1】:

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

标题:

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
.
.
.

主体:

.
.
.
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))
    

【讨论】:

以上是关于在 Swift 5/Swiftui 中重构 MapView(没有 Coordinators / UIViewRepresentables)的主要内容,如果未能解决你的问题,请参考以下文章

swift 在Swift中重构:设置闭包

代码重构:类重构规则(Swift版)

如何在 Swift 中重构重复的 Firestore 文档 ID?

从海量视图控制器中重构 Swift UIViewPropertyAnimators

重构map重构filter重构Some重构reduce方法重构flat函数

Swift 在淘宝商品评价的技术重构与实践