如何在 SwiftUI 的新地图视图中制作可点击的图钉?
How do I make a clickable pin in SwiftUI's new Map view?
我正在使用 SwiftUI 新地图视图来显示注释的图钉,并希望在单击图钉时显示用于编辑注释名称和描述的视图。
我尝试将 MapAnnotation 与包含带有 pin 图像的按钮的视图一起使用。图像显示正确,但按钮不起作用。
是否可以在不退回到 MKMapView 的 UIViewRepresentable 的情况下执行此操作?
import SwiftUI
import MapKit
struct ContentView: View {
@State private var showingEditScreen = false
@State private var region = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 37.334722,
longitude: -122.008889),
span: MKCoordinateSpan(latitudeDelta: 1,
longitudeDelta: 1)
)
@State private var pins: [Pin] = [
Pin(name: "Apple Park",
description: "Apple Inc. headquarters",
coordinate: CLLocationCoordinate2D(latitude: 37.334722,
longitude:-122.008889))
]
var body: some View {
Map(coordinateRegion: $region,
interactionModes: .all,
annotationItems: pins,
annotationContent: { pin in
MapAnnotation(coordinate: pin.coordinate,
content: {
PinButtonView(pin: pin)
})
})
}
}
我的 Pin 图定义:
struct Pin: Identifiable {
let id = UUID()
var name: String
var description: String
var coordinate: CLLocationCoordinate2D
}
带有按钮和图钉图像的视图:
struct PinButtonView: View {
@State private var showingEditScreen = false
@State var pin: Pin
var body: some View {
Button(action: {
showingEditScreen.toggle()
}) {
Image(systemName: "mappin")
.padding()
.foregroundColor(.red)
.font(.title)
}
.sheet(isPresented: $showingEditScreen,
content: {
EditView(pin: self.$pin)
})
}
}
编辑视图:
struct EditView: View {
@Environment(\.presentationMode) var presentationMode
@Binding var pin: Pin
var body: some View {
NavigationView {
Form {
TextField("Place name", text: $pin.name)
TextField("Description", text: $pin.description)
}
.navigationTitle("Edit place")
.navigationBarItems(trailing: Button("Done") {
self.presentationMode.wrappedValue.dismiss()
})
}
}
}
有了Xcode12个GM图钉还是难解难分
我有一个 SwiftUI MapKit 视图,它使用 MapAnnotations 和一个可点击的图钉,它显示一个包含信息的视图。
它不是很漂亮,但现在可以使用 iOS 仅限 14。
https://github.com/PhilStollery/BAB-Club-Search/blob/main/Shared/views/AnnotatedMapView.swift
import MapKit
import SwiftUI
struct AnnotatedMapView: View {
@ObservedObject
private var locationManager = LocationManager()
// Default to center on the UK, zoom to show the whole island
@State private var region = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 54.4609,
longitude: -3.0886),
span: MKCoordinateSpan(latitudeDelta: 10, longitudeDelta: 10))
@ObservedObject var store: ClubStore
var body: some View {
ZStack {
Map(coordinateRegion: $region,
showsUserLocation: true,
annotationItems: store.clubs!) {
club in MapAnnotation(coordinate: club.coordinate) {
VStack{
if club.show {
ZStack{
RoundedRectangle(cornerRadius: 10)
.fill(Color(UIColor.systemBackground))
.shadow(radius: 2, x: 2, y: 2)
VStack{
NavigationLink(destination: ClubLocationView(club: club)) {
Text(club.clubname)
.fontWeight(.bold)
}
.padding()
Text(club.association)
.padding(.leading)
.padding(.trailing)
Text(club.town)
.padding(.bottom)
}
}
.onTapGesture {
let index: Int = store.clubs!.firstIndex(where: {[=10=].id == club.id})!
store.clubs![index].show = false
}
} else {
Image(systemName: "house.circle")
.font(.title)
.foregroundColor(.accentColor)
.onTapGesture {
let index: Int = store.clubs!.firstIndex(where: {[=10=].id == club.id})!
store.clubs![index].show = true
}
}
}
}
}
.edgesIgnoringSafeArea(.bottom)
}
.navigationBarTitle(Text("Map View"), displayMode: .inline)
.navigationBarItems(trailing:
Button(action: {
withAnimation {
self.region.center = locationManager.current!.coordinate
self.region.span = MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)
}
})
{Image(systemName: "location")}
)
}
}
从 XCode 12.3 开始,这似乎可以与按钮一起使用。我注意到的一个关键问题是,如果您使用偏移量,那么您的按钮可能会被放置在注释的可点击区域之外。
为了解决这个问题,您可以添加额外的填充来解决偏移并将其保持在可点击范围内:
MapAnnotation(coordinate: item.placemark.coordinate) {
ZStack {
MapPinView() // My view for showing a precise pin
VStack { // A prompt with interactive option, offset by 60pt
Text("Use this location?")
HStack {
Button("Yes", action: {
print("yes")
})
Button("No", action: {
print("no")
})
}
}
.offset(x: 0, y: 60) // offset prompt so it's below the marker pin
}
.padding(.vertical, 60) // compensate for offset in tappable area of annotation. pad both the top AND the bottom to keep contents centered
}
我正在使用 SwiftUI 新地图视图来显示注释的图钉,并希望在单击图钉时显示用于编辑注释名称和描述的视图。
我尝试将 MapAnnotation 与包含带有 pin 图像的按钮的视图一起使用。图像显示正确,但按钮不起作用。
是否可以在不退回到 MKMapView 的 UIViewRepresentable 的情况下执行此操作?
import SwiftUI
import MapKit
struct ContentView: View {
@State private var showingEditScreen = false
@State private var region = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 37.334722,
longitude: -122.008889),
span: MKCoordinateSpan(latitudeDelta: 1,
longitudeDelta: 1)
)
@State private var pins: [Pin] = [
Pin(name: "Apple Park",
description: "Apple Inc. headquarters",
coordinate: CLLocationCoordinate2D(latitude: 37.334722,
longitude:-122.008889))
]
var body: some View {
Map(coordinateRegion: $region,
interactionModes: .all,
annotationItems: pins,
annotationContent: { pin in
MapAnnotation(coordinate: pin.coordinate,
content: {
PinButtonView(pin: pin)
})
})
}
}
我的 Pin 图定义:
struct Pin: Identifiable {
let id = UUID()
var name: String
var description: String
var coordinate: CLLocationCoordinate2D
}
带有按钮和图钉图像的视图:
struct PinButtonView: View {
@State private var showingEditScreen = false
@State var pin: Pin
var body: some View {
Button(action: {
showingEditScreen.toggle()
}) {
Image(systemName: "mappin")
.padding()
.foregroundColor(.red)
.font(.title)
}
.sheet(isPresented: $showingEditScreen,
content: {
EditView(pin: self.$pin)
})
}
}
编辑视图:
struct EditView: View {
@Environment(\.presentationMode) var presentationMode
@Binding var pin: Pin
var body: some View {
NavigationView {
Form {
TextField("Place name", text: $pin.name)
TextField("Description", text: $pin.description)
}
.navigationTitle("Edit place")
.navigationBarItems(trailing: Button("Done") {
self.presentationMode.wrappedValue.dismiss()
})
}
}
}
有了Xcode12个GM图钉还是难解难分
我有一个 SwiftUI MapKit 视图,它使用 MapAnnotations 和一个可点击的图钉,它显示一个包含信息的视图。
它不是很漂亮,但现在可以使用 iOS 仅限 14。
https://github.com/PhilStollery/BAB-Club-Search/blob/main/Shared/views/AnnotatedMapView.swift
import MapKit
import SwiftUI
struct AnnotatedMapView: View {
@ObservedObject
private var locationManager = LocationManager()
// Default to center on the UK, zoom to show the whole island
@State private var region = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 54.4609,
longitude: -3.0886),
span: MKCoordinateSpan(latitudeDelta: 10, longitudeDelta: 10))
@ObservedObject var store: ClubStore
var body: some View {
ZStack {
Map(coordinateRegion: $region,
showsUserLocation: true,
annotationItems: store.clubs!) {
club in MapAnnotation(coordinate: club.coordinate) {
VStack{
if club.show {
ZStack{
RoundedRectangle(cornerRadius: 10)
.fill(Color(UIColor.systemBackground))
.shadow(radius: 2, x: 2, y: 2)
VStack{
NavigationLink(destination: ClubLocationView(club: club)) {
Text(club.clubname)
.fontWeight(.bold)
}
.padding()
Text(club.association)
.padding(.leading)
.padding(.trailing)
Text(club.town)
.padding(.bottom)
}
}
.onTapGesture {
let index: Int = store.clubs!.firstIndex(where: {[=10=].id == club.id})!
store.clubs![index].show = false
}
} else {
Image(systemName: "house.circle")
.font(.title)
.foregroundColor(.accentColor)
.onTapGesture {
let index: Int = store.clubs!.firstIndex(where: {[=10=].id == club.id})!
store.clubs![index].show = true
}
}
}
}
}
.edgesIgnoringSafeArea(.bottom)
}
.navigationBarTitle(Text("Map View"), displayMode: .inline)
.navigationBarItems(trailing:
Button(action: {
withAnimation {
self.region.center = locationManager.current!.coordinate
self.region.span = MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)
}
})
{Image(systemName: "location")}
)
}
}
从 XCode 12.3 开始,这似乎可以与按钮一起使用。我注意到的一个关键问题是,如果您使用偏移量,那么您的按钮可能会被放置在注释的可点击区域之外。
为了解决这个问题,您可以添加额外的填充来解决偏移并将其保持在可点击范围内:
MapAnnotation(coordinate: item.placemark.coordinate) {
ZStack {
MapPinView() // My view for showing a precise pin
VStack { // A prompt with interactive option, offset by 60pt
Text("Use this location?")
HStack {
Button("Yes", action: {
print("yes")
})
Button("No", action: {
print("no")
})
}
}
.offset(x: 0, y: 60) // offset prompt so it's below the marker pin
}
.padding(.vertical, 60) // compensate for offset in tappable area of annotation. pad both the top AND the bottom to keep contents centered
}