我试图模仿苹果地图应用程序搜索按钮点击缩小功能的相同行为,但我无法做到这一点。
在Apple地图应用程序中,搜索地点并点击搜索结果项目后,它会在缩小时显示所有搜索结果项目注释,并显示用户当前位置(蓝点)和结果注释。
就我而言,我有 2 个 POI 按钮(如选项卡栏项目),当用户点击它们时,它会将查询字符串传递给 MKLocalSearch 并通过它显示结果。我想要的是,当点击按钮等选项卡栏项目时,我必须缩小结果和用户当前位置(蓝点)。
import SwiftUI
import MapKit
struct ContentView: View {
@State private var cameraPosition: MapCameraPosition = .userLocation(followsHeading: true, fallback: .automatic)
@State private var visibleRegion: MKCoordinateRegion?
@State private var searchResults: [MKMapItem] = []
@State private var selectedResult: MKMapItem?
@State private var route: MKRoute?
@State var isShowingBottomSheet = false
@StateObject var locationManager = LocationManager.shared
var body: some View {
if locationManager.state == .notDetermined {
LocationRequestView()
} else if locationManager.state == .denied {
LocationRequestDeniedView()
} else {
Map(position: $cameraPosition, selection: $selectedResult) {
Annotation("Current location", coordinate: .userLocation) {
}
.annotationTitles(.hidden)
ForEach(searchResults, id:\.self) {
Marker(item: $0)
}
.annotationTitles(.hidden)
if let route {
MapPolyline(route)
.stroke(.blue, lineWidth: 5)
}
}
.mapStyle(.standard(elevation: .realistic))
.safeAreaInset(edge: .bottom) {
HStack {
Spacer()
VStack(spacing: 0) {
if let selectedResult {
ItemInfoView(isShowing: $isShowingBottomSheet, route: $route, selectedTabBarButton: selectedTabBarButton, selectedResult: selectedResult, url: self.shareLocation())
.frame(height: 480)
.clipShape(RoundedRectangle(cornerRadius: 10))
.padding([.top, .horizontal])
.presentationContentInteraction(.scrolls)
}
Divider()
POIButtons(
position: $cameraPosition,
searchResults: $searchResults,
selectedTabBarButton: $selectedTabBarButton,
visibleRegion: visibleRegion
)
.padding(.top)
}
Spacer()
}
.background(.thinMaterial)
}
.onChange(of: searchResults) {
withAnimation {
cameraPosition = .userLocation(followsHeading: true, fallback: .automatic)
}
}
.onChange(of: selectedResult) {
let region = MKCoordinateRegion(
center: .userLocation,
span: MKCoordinateSpan(
latitudeDelta: 500,
longitudeDelta: 500))
cameraPosition = .region(region)
getDirections()
if selectedResult?.pointOfInterestCategory == .evCharger {
selectedTabBarButton = "EV"
} else {
selectedTabBarButton = "Gas"
}
}
.onMapCameraChange { context in
visibleRegion = context.region
}
.mapControls {
MapUserLocationButton()
MapCompass()
MapScaleView()
}
}
}
func getDirections() {
route = nil
isShowingBottomSheet = true
guard let selectedResult else { return }
let location = locationManager.manager.location
guard let coordinate = location?.coordinate else { return }
let request = MKDirections.Request ()
request.source = MKMapItem(placemark: MKPlacemark (coordinate: coordinate))
request.destination = selectedResult
Task {
let directions = MKDirections(request: request)
let response = try? await directions.calculate()
route = response?.routes.first
}
}
}
我尝试设置新的 MKCooperativeSpan 值并更改
cameraPosition = .region(with the new 'region')
这就是我为解决方案所做的;
简单来说,以下方法直接通过
coordinates: [CLLocationCoordinate2D]
计算最小和最大纬度和经度值,然后使用搜索结果计算 MKCoordinateRegion
的中心和跨度(在我的例子中,搜索功能是点击 EV 或 Gas Station 选项卡栏)纽扣)。我更新了上面ContentView中计算方法的用法。
func calculateRegionToFit(coordinates: [CLLocationCoordinate2D]) -> MKCoordinateRegion? {
// First check if the coordinates array is empty
guard !coordinates.isEmpty else {
return nil
}
// Find the minimum and maximum latitude and longitude values of the search
var minLat = coordinates[0].latitude
var maxLat = coordinates[0].latitude
var minLon = coordinates[0].longitude
var maxLon = coordinates[0].longitude
for coordinate in coordinates {
minLat = min(minLat, coordinate.latitude)
maxLat = max(maxLat, coordinate.latitude)
minLon = min(minLon, coordinate.longitude)
maxLon = max(maxLon, coordinate.longitude)
}
// Calculate the region based on the search values
let center = CLLocationCoordinate2D(latitude: (minLat + maxLat) / 2, longitude: (minLon + maxLon) / 2)
let span = MKCoordinateSpan(
latitudeDelta: maxLat - minLat,
longitudeDelta: maxLon - minLon
)
let region = MKCoordinateRegion(center: center, span: span)
return region
}