如何拦截 MKMapView 或 UIWebView 对象上的触摸事件?
我不确定我做错了什么,但我尝试捕捉 MKMapView
对象上的触摸。 我通过创建以下类对其进行子类化:
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
@interface MapViewWithTouches : MKMapView {
}
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *) event;
@end
和实现:
#import "MapViewWithTouches.h"
@implementation MapViewWithTouches
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *) event {
NSLog(@"hello");
//[super touchesBegan:touches withEvent:event];
}
@end
但看起来当我使用此类时,我在控制台上看不到任何内容:
MapViewWithTouches *mapView = [[MapViewWithTouches alloc] initWithFrame:self.view.frame];
[self.view insertSubview:mapView atIndex:0];
知道我做错了什么吗?
I'm not sure what I am doing wrong but I try to catch touches on a MKMapView
object. I subclassed it by creating the following class :
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
@interface MapViewWithTouches : MKMapView {
}
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *) event;
@end
And the implementation :
#import "MapViewWithTouches.h"
@implementation MapViewWithTouches
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *) event {
NSLog(@"hello");
//[super touchesBegan:touches withEvent:event];
}
@end
But it looks like when I use this class, I see nothing on the Console :
MapViewWithTouches *mapView = [[MapViewWithTouches alloc] initWithFrame:self.view.frame];
[self.view insertSubview:mapView atIndex:0];
Any idea what I'm doing wrong?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(15)
我发现实现这一目标的最佳方法是使用手势识别器。 其他方法被证明涉及大量黑客编程,这些编程不完美地复制了苹果的代码,特别是在多点触控的情况下。
这就是我所做的:实现一个无法阻止且无法阻止其他手势识别器的手势识别器。 将其添加到地图视图中,然后根据您的喜好使用gestureRecognizer的touchesBegan、touchesMoved等。
如何检测 MKMapView 内的任何点击(无技巧)
WildcardGestureRecognizer.h
WildcardGestureRecognizer.m
SWIFT 3
WildCardGestureRecognizer.swift
The best way I have found to achieve this is with a Gesture Recognizer. Other ways turn out to involve a lot of hackish programming that imperfectly duplicates Apple's code, especially in the case of multitouch.
Here's what I do: Implement a gesture recognizer that cannot be prevented and that cannot prevent other gesture recognizers. Add it to the map view, and then use the gestureRecognizer's touchesBegan, touchesMoved, etc. to your fancy.
How to detect any tap inside an MKMapView (sans tricks)
WildcardGestureRecognizer.h
WildcardGestureRecognizer.m
SWIFT 3
WildCardGestureRecognizer.swift
经过一天的披萨、尖叫之后,我终于找到了解决方案! 井井有条!
Peter,我使用了你上面的技巧,并对其进行了一些调整,最终得到了一个与 MKMapView 完美配合的解决方案,并且也应该与 UIWebView 配合使用
MKTouchAppDelegate.h
MKTouchAppDelegate.m
< strong>UIViewTouch.h
UIViewTouch.m
我希望这会对你们中的一些人有所帮助!
干杯
After a day of pizzas, screamings, I finally found the solution! Very neat!
Peter, I used your trick above and tweaked it a little bit to finally have a solution which work perfectly with MKMapView and should work also with UIWebView
MKTouchAppDelegate.h
MKTouchAppDelegate.m
UIViewTouch.h
UIViewTouch.m
I hope that will help some of you!
Cheers
对于 MKMapView 来说,真正可行的解决方案是手势识别!
当我拖动地图或捏合缩放时,我想停止更新我所在位置的地图中心。
因此,创建手势识别器并将其添加到 mapView :
查看 UIGestureRecognizer 类参考 查看所有可用的手势识别器。
因为我们已经将委托定义为 self,所以我们必须实现协议 UIGestureRecognizerDelegate :
并重写方法gestureRecognizer:gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:以便允许同时识别多个手势,如果我理解正确的话:
现在编写将由我们的手势识别器:
For a MKMapView the real working solution is with gesture recognization !
Me I wanted to stop updating the center of the map on my location when I drag the map or pinch to zoom.
So, create and add your gesture recognizer to the mapView :
Look the UIGestureRecognizer Class Reference to see all available gesture recognizer.
Because we've defined the delegate to self, we have to implement the protocole UIGestureRecognizerDelegate :
And override the methode gestureRecognizer:gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer: in order to allow recognize multiple gestures simultaneously, if I understood right :
Now write the methodes which will be called by our gesture recognizers :
以防万一有人尝试像我一样做同样的事情:我想在用户点击的位置创建注释。 为此,我使用了
UITapGestureRecognizer
解决方案:但是,当我点击注释时,也会调用
didTapOnMap:
并创建一个新注释。 解决方案是实现UIGestureRecognizerDelegate
:Just in case somebody is trying to do the same like me: I wanted to create an annotation at the point where the user taps. For that I used the
UITapGestureRecognizer
solution:However,
didTapOnMap:
was also called when I tapped on the annotation and a new one would be created. The solution is to implement theUIGestureRecognizerDelegate
:您可能需要覆盖一个透明视图来捕获触摸,就像通常使用基于 UIWebView 的控件所做的那样。 地图视图已经通过触摸完成了一系列特殊的操作,以便允许地图移动、居中、缩放等......消息不会被冒泡到您的应用程序中。
我能想到的另外两个(未经测试的)选项:
1)通过 IB 辞职第一响应者并将其设置为“文件所有者”以允许文件所有者响应触摸。 我怀疑这是否有效,因为 MKMapView 扩展了 NSObject,而不是 UIView,因此触摸事件仍然可能无法传播给您。
2) 如果您想在地图状态发生变化时捕获(例如缩放时),只需实现 MKMapViewDelegate 协议来侦听特定事件。 我的预感是,这是您轻松捕获某些交互的最佳机会(缺少在地图上实现透明视图的功能)。 不要忘记将容纳 MKMapView 的视图控制器设置为地图的委托 (
map.delegate = self
)。祝你好运。
You probably will need to overlay a transparent view to catch the touches just like is done so often with UIWebView-based controls. The Map View already does a bunch of special things with a touch in order to allow the map to be moved, centered, zoomed, etc... that the messages are not getting bubbled up to your app.
Two other (UNTESTED) options I can think of:
1) Resign the first responder via IB and set it to "File's Owner" to allow file's Owner to respond to the touches. I an dubious that this will work because MKMapView extends NSObject, not UIView ans a result the touch events still may not get propagated up to you.
2) If you want to trap when the Map state changes (such as on a zoom) just implement the MKMapViewDelegate protocol to listen for particular events. My hunch is this is your best shot at trapping some interaction easily (short of implementing the transparent View over the Map). Do not forget to set the View Controller housing the MKMapView as the map's delegate (
map.delegate = self
).Good Luck.
我还没有尝试过,但是 MapKit 很可能是基于类簇的,因此对其进行子类化是困难且无效的。
我建议将 MapKit 视图设置为自定义视图的子视图,这应该允许您在触摸事件到达之前拦截它们。
I haven't experimented, but there's a good chance MapKit is based around a class cluster, and therefore subclassing it is difficult and ineffective.
I'd suggest making the MapKit view a subview of a custom view, which should allow you to intercept touch events before they reach it.
因此,经过半天的折腾,我发现了以下内容:
在斯坦福大学的 iPhone 视频中,一位来自苹果公司的人说,许多 UIKit 的东西都会
如果你“转移”触摸请求(也就是上面描述的两种方法),会导致很多错误,而且你可能无法让它工作。
解决方案:此处描述:拦截/劫持MKMapView的iPhone触摸事件。 基本上,您可以在任何响应者获取事件之前“捕获”该事件,并在那里对其进行解释。
So after half a day of messing around with this I found the following:
In the Stanford iPhone videos, a guy from Apple says that many of the UIKit things will
cause alot of errors if you "transfer" the touch requests (aka the two methods described above), and you probably won't get it to work.
THE SOLUTION: is described here: Intercepting/Hijacking iPhone Touch Events for MKMapView. Basically you "catch" the event before any responder gets it, and interpret it there.
在 Swift 3.0 中
In Swift 3.0
使 MKMapView 成为自定义视图的子视图,并
在自定义视图中实现以返回 self 而不是子视图。
Make the MKMapView a subview of a custom view and implement
in the custom view to return self instead of the subview.
谢谢你的披萨和尖叫声——你节省了我很多时间。
multipletouchenabled 将偶尔工作。
最后,当我需要捕获触摸时,我切换了视图(与需要捏缩放的时间点不同):
Thanks for the pizza and screamings - you saved me lots of time.
multipletouchenabled will work sporadically.
In the end, I switched out the views when I needed to capture the touch (different point in time than needing pinchzooms):
我注意到您可以跟踪触摸的数量和位置,并获取视图中每个触摸的位置:
是否有其他人尝试使用这些值来更新地图的缩放级别? 这将是记录起始位置,然后记录结束位置,计算相对差异并更新地图的问题。
我正在使用 Martin 提供的基本代码,这看起来会起作用......
I notice that you can track the number and location of touches, and get the location of each in a view:
Has anyone else tried using these values to update the map's zoom level? It would be a matter of recording the start positions, and then the finish locations, calculating the relative difference and updating the map.
I'm playing with the basic code provided by Martin, and this looks like it will work...
这是我整理的,它确实允许在模拟器中进行捏缩放(尚未在真正的 iPhone 上尝试过),但我认为很好:
主要思想是,如果用户使用两根手指,则可以跟踪这些值。 我在 startPoints A 和 B 中记录起点和终点。然后记录当前的跟踪点,完成后,在 TouchsEnded 上,我可以调用一个例程来计算我开始的点之间的线的相对长度,以及使用简单斜边计算结束的点之间的线。 它们之间的比率就是缩放量:我将区域跨度乘以该量。
希望它对某人有用。
Here's what I put together, that does allow pinch zooms in the simulator (haven't tried on a real iPhone), but I think would be fine:
The main idea is that if the user is using two fingers, you track the values. I record the starting and ending points in startPoints A and B. Then I record the current tracking points, and when I'm done, on touchesEnded, I can call a routine to calculate the relative lengths of the line between the points I start with, and the line between the point I end with using simple hypotenuse calc. The ratio between them is the zoom amount: I multiply the region span by that amount.
Hope it's useful to someone.
我从 MystikSpiral 的回答中采用了“覆盖”透明视图的想法,它非常适合我想要实现的目标; 快速、干净的解决方案。
简而言之,我有一个自定义的 UITableViewCell (在 IB 中设计),左侧有一个 MKMapView,右侧有一些 UILabels。 我想制作自定义单元格,这样你就可以在任何地方触摸它,这将推动一个新的视图控制器。 然而,触摸地图并没有将触摸“向上”传递到 UITableViewCell,直到我简单地在其顶部添加了一个与地图视图大小相同的 UIView(在 IB 中),并使其背景成为代码中的“清晰颜色”(不认为你可以在 IB 中设置clearColor??):
认为它可能对其他人有帮助; 当然,如果您想为表视图单元格实现相同的行为。
I took the idea of an "overlay" transparent view, from MystikSpiral's answer, and it worked perfectly for what I was trying to achieve; quick, and clean solution.
In short, I had a custom UITableViewCell (designed in IB) with a MKMapView on the left-hand-side and some UILabels on the right. I wanted to make the custom cell so you could touch it anywhere and this would push a new view controller. However touching the map didn't pass touches 'up' to the UITableViewCell until I simply added a UIView of the same size as the map view right on top of it (in IB) and made it's background the 'clear color' in code (don't think you can set clearColor in IB??):
Thought it might help someone else; certainly if you want to achieve the same behaviour for a table view cell.
我不明白为什么其他答案如此复杂。 解决方案实际上只有一行:
I don't understand why other answers are so complicated. The solution is really just one line: