SwiftUI 视图阻止触摸 MapKit 而不是其他视图
SwiftUI Views blocking touches to MapKit but not other views
我正在通过 UIViewRepresentable 呈现一个 mapView,并希望在地图的中心有一个图像 'target'。此图像会阻止在图像上启动的点击事件和平移手势。因此,将注释放到图像下方的地图上意味着无法启动其标注。
我已阅读有关透明度的问题,因此我将 'clear' 区域的目标图像重新制作为白色,不透明度为 1%,但行为没有变化。
将 allowsHitTesting
设置为 false 也不起作用,尽管如果我在图像下方插入一个按钮(代码中的测试 1)我可以点击它,而不是 map/annotation 所以似乎是 MapKit 元素和我自己添加的 SwiftUI 视图之间的区别。
import SwiftUI
import MapKit
struct ContentView: View {
var body: some View {
ZStack {
MapView()
/*Test 1*/ Button("Tap Me") {
print("Text button was tapped")
}
Image("target")
.frame(width: 90, height: 90)
.allowsHitTesting(false)
/*Test 2*/ Rectangle()
.fill(Color.red.opacity(0.2))
.frame(width: 90, height: 90)
.allowsHitTesting(false)
/*Test 3*/ Button(action: {print("Round button was tapped")}) {
Circle()
.fill(Color.red.opacity(0.2))
.frame(width: 90, height: 90)
}
.allowsHitTesting(false)
.disabled(true)
}
}
}
struct MapView: UIViewRepresentable {
func makeUIView(context: Context) -> MKMapView {
let map = MKMapView()
map.mapType = .standard
map.isRotateEnabled = false
let location = CLLocation(latitude: 40.763783, longitude: -73.973133)
let region = MKCoordinateRegion(center: location.coordinate, latitudinalMeters: 2000, longitudinalMeters: 2000)
map.setRegion(region, animated: true)
let annotation = MyAnnotation(coordinate: location.coordinate)
annotation.title = "Title"
annotation.subtitle = "Subtitle"
map.addAnnotation(annotation)
return map
}
func updateUIView(_ uiView: MKMapView, context: Context) {
}
}
class MyAnnotation: NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D
var title: String?
var subtitle: String?
init(coordinate: CLLocationCoordinate2D) {
self.coordinate = coordinate
}
}
将图像换成矩形(代码中的测试 2)具有相同的行为,我可以与我添加的视图进行交互,但无法将我的 touches/pans 传递给 MapKit 元素。我什至尝试使用禁用的 Button,希望它的命中测试更符合我想要实现的目标。可惜没有。
有谁知道通过另一个视图与 mapView、点击和平移进行交互的方法吗?
是的,到目前为止,即使是透明图像也不允许 hit-through。在您的情况下,很简单,可能的方法是创建自定义形状,如下所示。形状会通过命中。
这里有一个简单的形状演示来显示方向。
struct Cross: Shape {
func path(in rect: CGRect) -> Path {
return Path { path in
path.move(to: CGPoint(x: rect.midX, y: 0))
path.addLine(to: CGPoint(x: rect.midX, y: rect.maxY))
path.move(to: CGPoint(x: 0, y: rect.midY))
path.addLine(to: CGPoint(x: rect.maxX, y: rect.midY))
path.move(to: CGPoint(x: rect.midX, y: rect.midY))
path.addArc(center: CGPoint(x: rect.midX, y: rect.midY), radius: 10, startAngle: Angle(degrees: 0), endAngle: Angle(degrees: 360), clockwise: false)
}
}
}
struct ContentView: View {
var body: some View {
ZStack {
MapView()
Cross().stroke(Color.red)
.frame(width: 90, height: 90)
}
}
}
如果您禁用以上所有功能,则可以使用...
所以按钮 "tap me" 有效。
struct ContentView: View {
var body: some View {
ZStack {
MapView()
/*Test 1*/ Button("Tap Me") {
print("Text button was tapped")
}
Image("target")
.frame(width: 90, height: 90)
.allowsHitTesting(false)
.allowsHitTesting(false)
.disabled(true)
/*Test 2*/ Rectangle()
.fill(Color.red.opacity(0.2))
.frame(width: 90, height: 90)
.allowsHitTesting(false)
.allowsHitTesting(false)
.disabled(true)
/*Test 3*/ Button(action: {print("Round button was tapped")}) {
Circle()
.fill(Color.red.opacity(0.2))
.frame(width: 90, height: 90)
}
.allowsHitTesting(false)
.disabled(true)
}
}
}
我正在通过 UIViewRepresentable 呈现一个 mapView,并希望在地图的中心有一个图像 'target'。此图像会阻止在图像上启动的点击事件和平移手势。因此,将注释放到图像下方的地图上意味着无法启动其标注。
我已阅读有关透明度的问题,因此我将 'clear' 区域的目标图像重新制作为白色,不透明度为 1%,但行为没有变化。
将 allowsHitTesting
设置为 false 也不起作用,尽管如果我在图像下方插入一个按钮(代码中的测试 1)我可以点击它,而不是 map/annotation 所以似乎是 MapKit 元素和我自己添加的 SwiftUI 视图之间的区别。
import SwiftUI
import MapKit
struct ContentView: View {
var body: some View {
ZStack {
MapView()
/*Test 1*/ Button("Tap Me") {
print("Text button was tapped")
}
Image("target")
.frame(width: 90, height: 90)
.allowsHitTesting(false)
/*Test 2*/ Rectangle()
.fill(Color.red.opacity(0.2))
.frame(width: 90, height: 90)
.allowsHitTesting(false)
/*Test 3*/ Button(action: {print("Round button was tapped")}) {
Circle()
.fill(Color.red.opacity(0.2))
.frame(width: 90, height: 90)
}
.allowsHitTesting(false)
.disabled(true)
}
}
}
struct MapView: UIViewRepresentable {
func makeUIView(context: Context) -> MKMapView {
let map = MKMapView()
map.mapType = .standard
map.isRotateEnabled = false
let location = CLLocation(latitude: 40.763783, longitude: -73.973133)
let region = MKCoordinateRegion(center: location.coordinate, latitudinalMeters: 2000, longitudinalMeters: 2000)
map.setRegion(region, animated: true)
let annotation = MyAnnotation(coordinate: location.coordinate)
annotation.title = "Title"
annotation.subtitle = "Subtitle"
map.addAnnotation(annotation)
return map
}
func updateUIView(_ uiView: MKMapView, context: Context) {
}
}
class MyAnnotation: NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D
var title: String?
var subtitle: String?
init(coordinate: CLLocationCoordinate2D) {
self.coordinate = coordinate
}
}
将图像换成矩形(代码中的测试 2)具有相同的行为,我可以与我添加的视图进行交互,但无法将我的 touches/pans 传递给 MapKit 元素。我什至尝试使用禁用的 Button,希望它的命中测试更符合我想要实现的目标。可惜没有。
有谁知道通过另一个视图与 mapView、点击和平移进行交互的方法吗?
是的,到目前为止,即使是透明图像也不允许 hit-through。在您的情况下,很简单,可能的方法是创建自定义形状,如下所示。形状会通过命中。
这里有一个简单的形状演示来显示方向。
struct Cross: Shape {
func path(in rect: CGRect) -> Path {
return Path { path in
path.move(to: CGPoint(x: rect.midX, y: 0))
path.addLine(to: CGPoint(x: rect.midX, y: rect.maxY))
path.move(to: CGPoint(x: 0, y: rect.midY))
path.addLine(to: CGPoint(x: rect.maxX, y: rect.midY))
path.move(to: CGPoint(x: rect.midX, y: rect.midY))
path.addArc(center: CGPoint(x: rect.midX, y: rect.midY), radius: 10, startAngle: Angle(degrees: 0), endAngle: Angle(degrees: 360), clockwise: false)
}
}
}
struct ContentView: View {
var body: some View {
ZStack {
MapView()
Cross().stroke(Color.red)
.frame(width: 90, height: 90)
}
}
}
如果您禁用以上所有功能,则可以使用...
所以按钮 "tap me" 有效。
struct ContentView: View {
var body: some View {
ZStack {
MapView()
/*Test 1*/ Button("Tap Me") {
print("Text button was tapped")
}
Image("target")
.frame(width: 90, height: 90)
.allowsHitTesting(false)
.allowsHitTesting(false)
.disabled(true)
/*Test 2*/ Rectangle()
.fill(Color.red.opacity(0.2))
.frame(width: 90, height: 90)
.allowsHitTesting(false)
.allowsHitTesting(false)
.disabled(true)
/*Test 3*/ Button(action: {print("Round button was tapped")}) {
Circle()
.fill(Color.red.opacity(0.2))
.frame(width: 90, height: 90)
}
.allowsHitTesting(false)
.disabled(true)
}
}
}