6

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

  1. 放大手势总是被解释为缩小
  2. 任何缩放手势都不会实时更新地图的视图。

在 hitTest 中,如果我返回“地图”视图,MKMapView 功能效果很好,但我没有机会拦截事件。

有任何想法吗?

MyMapView.h:

@interface MyMapView : MKMapView
{
    UIView      *map;
}

我的地图视图.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];
}
4

6 回答 6

8

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

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

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

如何检测 MKMapView 内的任何点击(无技巧)

WildcardGestureRecognizer * tapInterceptor = [[WildcardGestureRecognizer alloc] init];
 tapInterceptor.touchesBeganCallback = ^(NSSet * touches, UIEvent * event) {
  self.lockedOnUserLocation = NO;
 };
 [mapView addGestureRecognizer:tapInterceptor];

通配符手势识别器.h

//
//  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

通配符手势识别器.m

//
//  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
于 2010-10-31T18:53:25.960 回答
5

我有同样的问题 - 我想在地图视图上绘制地图比例。为了做到这一点,我必须拦截触摸事件,然后将它们发送回地图视图。不幸的是,当 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];
}
  1. 我已将应用程序的主窗口设为 MyMainWindow 的实例。

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

于 2009-09-05T13:55:06.507 回答
2
#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

此代码将检测触摸以及缩放。

于 2010-09-16T07:45:16.010 回答
1

尝试

[super touchesEnded:touches withEvent:event];

代替

[map touchesEnded:touches withEvent:event];

并将这个想法应用到所有的触摸事件方法中。这样,触摸应该沿着响应链传递,并且将恢复和平。

于 2009-08-19T07:38:04.713 回答
1

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

  1. 给地图视图一个标签,比如 99
  2. 当我接触到时,向上遍历接收视图的视图层次结构,寻找带有上述标签的视图。

这是代码:

// 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
于 2010-05-09T08:43:49.813 回答
0

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

于 2009-07-13T21:09:03.503 回答