在 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 中重构重复的 Firestore 文档 ID?
从海量视图控制器中重构 Swift UIViewPropertyAnimators