Я использую функции MapKit + iOS 17 для отображения карты с местоположением пользователя. Я хотел бы нарисовать радиус 30 метров вокруг UserLocation. Как я могу это сделать? Я видел некоторые решения 12-летней давности, но полагаю, что сейчас есть лучший способ сделать это.
struct Home: View {
@State private var position: MapCameraPosition = .userLocation(fallback: .automatic)
@State private var visibleRegion: MKCoordinateRegion?
@State private var searchResults: [MKMapItem] = []
@State private var selectedResult: MKMapItem?
@State private var showDetails: Bool = false
@State private var lookAroundScene: MKLookAroundScene?
let locationManager = CLLocationManager()
var body: some View {
Map(position: $position, selection: $selectedResult) {
let customLocations: [MKMapItem] = [
createMapItem(name: "Via Palamos", coordinate: .viaPalamos),
createMapItem(name: "Larry Way", coordinate: .larryWay),
]
ForEach(customLocations, id: \.self) { result in
Marker(result.name ?? "Unknown Location", systemImage: "binoculars.fill", coordinate: result.placemark.coordinate)
.tint(.blue)
}
.annotationTitles(.hidden)
UserAnnotation()
}
.mapStyle(.standard(pointsOfInterest: .excludingAll))
.mapStyle(.standard(elevation: .realistic))
.sheet(isPresented: $showDetails, onDismiss: {
withAnimation(.snappy) {
}
}, content: {
MapDetails()
.presentationDetents([.height(750)])
.presentationBackgroundInteraction(.enabled(upThrough: .height(750)))
.presentationCornerRadius(25)
.interactiveDismissDisabled(true)
})
.onAppear {
locationManager.requestWhenInUseAuthorization()
}
//MARK: This could help animate it nicely, i think safe inset view is causing interference atm though
// .animation(.easeIn)
.onChange(of: searchResults) {
position = .automatic
}
.onChange(of: selectedResult) { oldValue, newValue in
/// Displaying Details about the Selected Place
showDetails = newValue != nil
/// Fetching Look Around Preview, when ever selection Changes
fetchLookAroundPreview()
}
.onMapCameraChange { context in
visibleRegion = context.region
}
.mapControls {
VStack {
MapUserLocationButton()
//MARK: Can I make it pitch more by defualt? and make it the automaitic mode on initilisation
MapPitchToggle()
MapCompass()
MapScaleView()
}
.buttonBorderShape(.circle)
}
}
}
Как я могу рассчитать радиус 30 метров вокруг местоположения пользователя и отобразить его на карте? Ему также необходимо будет обновляться по мере изменения местоположения пользователя. Поэтому, когда пользователь перемещается, круг радиусом 30 метров движется вместе с ним.





Простым решением было бы иметь MapCircle, который меняет свое местоположение в соответствии с обновлениями местоположения из CLLocationManager.
Вот простой пример, который показывает полупрозрачный красный круг вокруг местоположения пользователя.
@Observable
class LocationTracker: NSObject, CLLocationManagerDelegate {
var location: CLLocationCoordinate2D? = nil
let manager = CLLocationManager()
override init() {
super.init()
manager.delegate = self
manager.requestWhenInUseAuthorization()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
location = locations.first?.coordinate
}
deinit {
manager.stopUpdatingLocation()
}
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
print("Changed", manager.authorizationStatus.rawValue)
if manager.authorizationStatus == .authorizedWhenInUse {
manager.startUpdatingLocation()
}
}
}
struct ContentView: View {
@State var manager: LocationTracker?
var body: some View {
Map {
UserAnnotation.init { loc in
Circle()
}
if let c = manager?.location {
MapCircle(center: c, radius: 30)
.foregroundStyle(.red.opacity(0.5))
}
}
.onAppear {
manager = LocationTracker()
}
}
}
Тем не менее, круг обновляется только один или два раза в секунду, поскольку существует ограничение на частоту вызова didUpdateLocations.
@Schwifty Да. См. документацию .
Выглядит великолепно, радиус 30 означает 30 метров?