我目前正在学习 Swift(在 Xcode 中),并且正在尝试制作一个应用程序。我一直在按照教程在 Mapkit 中制作路线。
目前,我拥有它,以便用户可以输入一个位置,它会创建一条到该位置的路线。有什么办法可以让它创建一个循环吗?
基本上会发生的情况是,它会映射一条到该位置的路线(例如地址、星巴克等),然后掉头继续沿着路线回到起点(但不只是以同样的方式穿越回去,它会覆盖不同的街道)。
希望这是有道理的,这是我的代码:
//
// ContentView.swift
// NavNinja
//
// Created by Dakota on 2/11/24.
//
import SwiftUI
import MapKit
struct ContentView: View {
@State private var cameraPosition: MapCameraPosition = .region(.userRegion)
@State private var searchText = ""
@State private var results = [MKMapItem]()
@State private var mapSelection: MKMapItem?
@State private var showDetails = false
@State private var getDirections = false
//ROUTE
@State private var routeDisplaying = false
@State private var route: MKRoute?
@State private var routeDestination: MKMapItem?
@State private var routeDistanceInMiles: Double = 0.0
//ROUTE
var body: some View {
Map(position: $cameraPosition, selection: $mapSelection) {
UserAnnotation()
Annotation("My location", coordinate: .userLocation) {
ZStack {
Circle()
.frame(width: 32, height: 32)
.foregroundStyle(.blue.opacity(0.25))
Circle()
.frame(width: 20, height: 20)
.foregroundStyle(.white)
Circle()
.frame(width: 12, height: 12)
.foregroundStyle(.blue)
}
}
ForEach(results, id: \.self) { item in
if routeDisplaying {
if item == routeDestination {
let placemark = item.placemark
Marker(placemark.name ?? "", coordinate: placemark.coordinate)
}
} else {
let placemark = item.placemark
Marker(placemark.name ?? "", coordinate: placemark.coordinate)
}
}
//ROUTE
if let route {
MapPolyline(route.polyline)
.stroke(.blue, lineWidth: 6)
}
//ROUTE
}
.overlay(alignment: .top) {
TextField("Search for a location...", text: $searchText)
.font(.subheadline)
.padding(22)
.background(.white)
.padding()
.shadow(radius: 10)
}
// Add route distance display
.overlay(alignment: .bottomTrailing) {
if route != nil {
Text(String(format: "Route Distance: %.2f miles", routeDistanceInMiles))
.font(.footnote)
.foregroundColor(.white)
.padding(8)
.background(Color.black.opacity(0.7))
.cornerRadius(8)
.padding(10)
}
}
.onSubmit(of: /*@START_MENU_TOKEN@*/.text/*@END_MENU_TOKEN@*/) {
Task { await searchPlaces() }
}
//ROUTE
.onChange(of: getDirections, { oddValue, newValue in
if newValue {
fetchRoute()
}
})
//ROUTE
.onChange(of: mapSelection, { addValue, newValue in
showDetails = newValue != nil
})
.sheet(isPresented: $showDetails, content: {
LocationDetailsView(mapSelection: $mapSelection,
show: $showDetails,
getDirections: $getDirections)
.presentationDetents([.height(340)])
.presentationBackgroundInteraction(.enabled(upThrough: .height(340)))
.presentationCornerRadius(12)
})
.mapControls {
MapCompass()
MapPitchToggle()
MapUserLocationButton()
}
}
}
extension ContentView {
func searchPlaces() async {
let request = MKLocalSearch.Request()
request.naturalLanguageQuery = searchText
request.region = .userRegion
let results = try? await MKLocalSearch(request: request).start()
self.results = results?.mapItems ?? []
}
//ROUTE
func fetchRoute() {
if let mapSelection {
let request = MKDirections.Request()
request.source = MKMapItem(placemark: .init(coordinate: .userLocation))
request.destination = mapSelection
Task {
let result = try? await MKDirections(request: request).calculate()
route = result?.routes.first
routeDestination = mapSelection
withAnimation(.snappy) {
routeDisplaying = true
showDetails = false
if let rect = route?.polyline.boundingMapRect, routeDisplaying {
cameraPosition = .rect(rect)
}
// Calculate the total distance of the route in miles
if let totalDistanceInMeters = route?.distance {
// Convert meters to miles
let totalDistanceInMiles = totalDistanceInMeters / 1609.34 // 1 mile = 1609.34 meters
routeDistanceInMiles = totalDistanceInMiles
}
}
}
}
}
//ROUTE
}
extension CLLocationCoordinate2D {
static var userLocation: CLLocationCoordinate2D {
return .init(latitude: 25.7602, longitude: -80.1959)
}
}
extension MKCoordinateRegion {
static var userRegion: MKCoordinateRegion {
return .init(center: .userLocation,
latitudinalMeters: 1000,
longitudinalMeters: 1000)
}
}
#Preview {
ContentView()
}
两个“//ROUTE”注释之间的所有代码都表明该代码与映射路线有关。
使用 MKRoute.Step 在路线中添加步骤以强制使用不同方向的循环 每个 MKRoute.Step 对象都对应于人们在两点之间导航时需要遵循的单个指令。例如,一个步骤可能涉及沿着一条道路行驶,直到继续沿该路线需要转弯为止。