拦截/劫持MKMapView的iPhone Touch事件

拦截/劫持MKMapView的iPhone Touch事件,iphone,events,gesture-recognition,Iphone,Events,Gesture Recognition,3.0 SDK中是否存在禁用实时缩放和拦截MKMapView放大手势的错误?我有一些真正简单的代码,因此我可以检测tap事件,但有两个问题: 放大手势始终被解释为缩小 所有缩放手势都不会实时更新地图的视图 在hitTest中,如果我返回“map”视图,MKMapView功能工作得很好,但我没有机会截获事件 有什么想法吗 MyMapView.h: @interface MyMapView : MKMapView { UIView *map; } MyMapView.m: - (

3.0 SDK中是否存在禁用实时缩放和拦截MKMapView放大手势的错误?我有一些真正简单的代码,因此我可以检测tap事件,但有两个问题:

  • 放大手势始终被解释为缩小
  • 所有缩放手势都不会实时更新地图的视图
  • 在hitTest中,如果我返回“map”视图,MKMapView功能工作得很好,但我没有机会截获事件

    有什么想法吗

    MyMapView.h:

    @interface MyMapView : MKMapView
    {
        UIView      *map;
    }
    
    MyMapView.m:

    - (id)initWithFrame:(CGRect)frame
    {
        if (![super initWithFrame:frame])
            return nil;
    
        self.multipleTouchEnabled = true;
    
        return self;
    }
    
    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
        NSLog(@"Hit Test");
        map = [super hitTest:point withEvent:event];
        return self;
    }
    
    - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
    {
        NSLog(@"%s", __FUNCTION__);
        [map touchesCancelled:touches withEvent:event];
    }
    
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent*)event
    {
        NSLog(@"%s", __FUNCTION__);
        [map touchesBegan:touches withEvent:event];
    }
    
    - (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
    {
        NSLog(@"%s, %x", __FUNCTION__, mViewTouched);
        [map touchesMoved:touches withEvent:event];
    }
    
    - (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
    {
        NSLog(@"%s, %x", __FUNCTION__, mViewTouched);
        [map touchesEnded:touches withEvent:event];
    }
    

    MKMapView不响应上面列出的触摸方法…

    请尝试

    [super-touchesend:toucheevent:event]

    而不是

    [map touchesEnded:TouchwithEvent:event]


    并将此思想应用到所有触摸事件方法中。这样,触碰应该沿着响应链向下移动,和平就会恢复。

    我也遇到了同样的问题-我想在地图视图的顶部绘制地图比例。为了做到这一点,我必须截取触摸事件,然后将它们发送回地图视图。不幸的是,当MKMapView不是事件的原始接收器时,一些平滑的平移和缩放动画不再工作

    然而,我已经找到了这个问题的解决方案——有点老套,但很有效: 1.我已将我的MapScales UIView放在MKMapView的顶部,并关闭了在其中接收事件的功能,因此默认情况下,底层MKMapView会接收事件。 2.我用MyMainWindow类将UIWindow子类化,并在其中重写了方法:

    - (void) sendEvent:(UIEvent*)event {
      [super sendEvent:event];
      [self send_the_event_also_to_my_MapScales_component_with_use_of_listener_design_pattern];
    }
    
  • 我已经将我的应用程序的主窗口设置为我的主窗口

  • 通过这种方式,我的MapScales组件可以接收所有触摸事件并对其作出反应,同时不会破坏底层的MKMapView:)

    要扩展@chomasek的答案,为了只处理地图视图的这些触摸,我执行以下操作:

  • 给地图视图一个标签,比如99
  • 当我接触时,向上遍历接收视图的视图层次结构,寻找具有上述标记的视图
  • 代码如下:

    // this is in the view controller containing the map view
    // kICTagForMapView is just a constant
    _mapView.tag = kICTagForMapView;
    
    然后在
    sendEvent:

    // this does into the UIWindow subclass
    BOOL isMapView = NO;    
    UIView* superView = touch.view.superview;
    while(superView)
    {
        //Debug(@"superView = %@", superView);
        if (superView.tag == kICTagForMapView)
        {
            isMapView = YES;
            break;
        }
        superView = superView.superview;
    }
    
    if (isMapView == NO) return;
    
    // do stuff here
    
    #导入
    #导入“UIViewTouch.h”
    #进口
    @接口MapTouchAppDelegate:NSObject
    {
    UIViewTouch*viewTouch;
    MKMapView*mapView;
    UIWindow*窗口;
    }
    @属性(非原子,保留)IBUIWindow*window;
    @属性(非原子,保留)UIViewTouch*viewTouch;
    @属性(非原子,保留)MKMapView*mapView;
    @结束
    #导入“MapTouchAppDelegate.h”
    @实现MapTouchAppDelegate
    @合成窗口;
    @综合视觉触觉;
    @综合地图视图;
    -(无效)应用程序IDFinishLaunching:(UIApplication*)应用程序
    {    
    //我们创建一个视图,它将捕获事件发生时的情况并将其记录在控制台中
    viewTouch=[[UIViewTouch alloc]initWithFrame:CGRectMake(0,0320480)];
    //接下来,我们创建MKMapView对象,它将作为viewTouch的子视图添加
    mapView=[[MKMapView alloc]initWithFrame:CGRectMake(0,0320480)];
    [viewTouch addSubview:mapView];
    //我们展示一切!
    [窗口添加子视图:视图触摸];
    //应用程序启动后自定义的覆盖点
    [WindowMakeKeyandVisible];
    }
    -(无效)解除锁定{
    [窗口释放];
    [super dealoc];
    }
    #进口
    @界面UIViewTouch:UIView
    {
    UIView*viewTouched;
    }
    @属性(非原子,保留)UIView*viewTouched;
    -(UIView*)hitTest:(CGPoint)point with event:(UIEvent*)event;
    -(无效)触摸开始:(NSSet*)触摸事件:(UIEvent*)事件;
    -(无效)触摸移动:(NSSet*)触摸事件:(UIEvent*)事件;
    -(void)touchesend:(NSSet*)toucheevent:(UIEvent*)event;
    -(void)touchscancelled:(NSSet*)touchsevent:(UIEvent*)event;
    @结束
    #导入“UIViewTouch.h”
    @UIViewTouch的实现
    @综合观察;
    //这里的基本思想是截取作为hitTest中的第一响应者发送回来的视图。
    //我们将其精确地保存在属性视图中,并作为第一响应者返回视图。
    -(UIView*)hitTest:(CGPoint)point with event:(UIEvent*)event
    {
    NSLog(“命中测试”);
    self.multipleTouchEnabled=true;
    viewTouched=[super hitTest:PointWithEvent:event];
    回归自我;
    }
    //然后,当一个事件被触发时,我们记录这个事件,然后将它发送回我们保存的viewTouch,瞧!!!:)
    -(无效)触摸开始:(NSSet*)触摸事件:(UIEvent*)事件
    {
    NSLog(@“触摸开始”);
    [查看触摸开始:触摸事件:事件];
    }
    -(无效)触摸移动:(NSSet*)触摸事件:(UIEvent*)事件
    {
    NSLog(“触摸移动”);
    [查看触摸移动:触摸事件:事件];
    }
    -(void)touchesend:(NSSet*)toucheevent:(UIEvent*)event
    {
    NSLog(@“触摸结束”);
    [查看触摸已解除:触摸事件:事件];
    }
    -(无效)触控取消:(NSSet*)触控事件:(UIEvent*)事件
    {
    NSLog(“触摸取消”);
    }
    @结束
    

    此代码将检测触摸和缩放。

    我发现实现这一点的最佳方法是使用手势识别器。不清楚您是想自己识别缩放事件,还是只想检测用户何时进行缩放/平移

    我不需要检测地图平移或缩放——我只关心用户是否将手指放在MKMapView中的任何位置。如果您需要以100%的召回率和准确率检测缩放或平移,则可能比这更复杂。我们真正需要的是MKMapView的开源实现,这样我们就可以将它添加到委托中,以及许多其他功能中

    我要做的是:实现一个无法阻止的手势识别器,也无法阻止其他手势识别器。将其添加到地图视图,并根据需要处理相关触摸事件

    如何检测MKMapView中的任何点击(SAN技巧) wildcardGestureRecognitor.h
    我不相信。通过将事件传递到地图视图,地图可以平移和缩小。“何时”地图
    #import <UIKit/UIKit.h>
    #import "UIViewTouch.h"
    #import <MapKit/MapKit.h>
    
    @interface MapTouchAppDelegate : NSObject <UIApplicationDelegate>
    {
        UIViewTouch *viewTouch;
        MKMapView *mapView;
        UIWindow *window;
    }
    
    @property (nonatomic, retain) IBOutlet UIWindow *window;
    @property (nonatomic, retain) UIViewTouch *viewTouch;
    @property (nonatomic, retain) MKMapView *mapView;
    
    @end
    
    
    #import "MapTouchAppDelegate.h"
    
    @implementation MapTouchAppDelegate
    
    @synthesize window;
    @synthesize viewTouch;
    @synthesize mapView;
    
    - (void)applicationDidFinishLaunching:(UIApplication *)application
    {    
        //We create a view wich will catch Events as they occured and Log them in the Console
        viewTouch = [[UIViewTouch alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
    
        //Next we create the MKMapView object, which will be added as a subview of viewTouch
        mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
        [viewTouch addSubview:mapView];
    
        //And we display everything!
        [window addSubview:viewTouch];
        // Override point for customization after application launch
        [window makeKeyAndVisible];
    }
    
    
    - (void)dealloc {
        [window release];
        [super dealloc];
    }
    
    #import <UIKit/UIKit.h>
    
    
    @interface UIViewTouch : UIView
    {
        UIView *viewTouched;
    }
    @property (nonatomic, retain) UIView * viewTouched;
    
    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
    
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
    - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
    
    @end
    
    
    #import "UIViewTouch.h"
    
    
    @implementation UIViewTouch
    
    @synthesize viewTouched;
    
    //The basic idea here is to intercept the view which is sent back as the firstresponder in hitTest.
    //We keep it preciously in the property viewTouched and we return our view as the firstresponder.
    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 
    {
        NSLog(@"Hit Test");
        self.multipleTouchEnabled = true;
        viewTouched = [super hitTest:point withEvent:event];
        return self;
    }
    
    //Then, when an event is fired, we log this one and then send it back to the viewTouched we kept, and voilà!!! :)
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
    {
        NSLog(@"Touch Began");
    
        [viewTouched touchesBegan:touches withEvent:event];
    }
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
    {
        NSLog(@"Touch Moved");
        [viewTouched touchesMoved:touches withEvent:event];
    }
    
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 
    {
        NSLog(@"Touch Ended");
        [viewTouched touchesEnded:touches withEvent:event];
    }
    
    - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
    {
        NSLog(@"Touch Cancelled");
    }
    
    
    @end
    
    WildcardGestureRecognizer * tapInterceptor = [[WildcardGestureRecognizer alloc] init];
     tapInterceptor.touchesBeganCallback = ^(NSSet * touches, UIEvent * event) {
      self.lockedOnUserLocation = NO;
     };
     [mapView addGestureRecognizer:tapInterceptor];
    
    //
    //  WildcardGestureRecognizer.h
    //  Copyright 2010 Floatopian LLC. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    typedef void (^TouchesEventBlock)(NSSet * touches, UIEvent * event);
    
    @interface WildcardGestureRecognizer : UIGestureRecognizer {
     TouchesEventBlock touchesBeganCallback;
    }
    @property(copy) TouchesEventBlock touchesBeganCallback;
    
    
    @end
    
    //
    //  WildcardGestureRecognizer.m
    //  Created by Raymond Daly on 10/31/10.
    //  Copyright 2010 Floatopian LLC. All rights reserved.
    //
    
    #import "WildcardGestureRecognizer.h"
    
    
    @implementation WildcardGestureRecognizer
    @synthesize touchesBeganCallback;
    
    -(id) init{
     if (self = [super init])
     {
      self.cancelsTouchesInView = NO;
     }
     return self;
    }
    
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
     if (touchesBeganCallback)
      touchesBeganCallback(touches, event);
    }
    
    - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
    {
    }
    
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    {
    }
    
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
    {
    }
    
    - (void)reset
    {
    }
    
    - (void)ignoreTouch:(UITouch *)touch forEvent:(UIEvent *)event
    {
    }
    
    - (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer
    {
     return NO;
    }
    
    - (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer
    {
     return NO;
    }
    
    @end