Перехват / похищение событий iPhone Touch для MKMapView - PullRequest
6 голосов
/ 14 июля 2009

Есть ли ошибка в 3.0 SDK, которая отключает масштабирование в реальном времени и перехват жеста увеличения для MKMapView? У меня есть некоторый очень простой код, чтобы я мог обнаружить события касания, но есть две проблемы:

  1. жест увеличения всегда интерпретируется как уменьшение масштаба
  2. ни один из жестов масштабирования не обновляет вид карты в реальном времени.

В hitTest, если я возвращаю представление "карта", функциональность 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];
}

Ответы [ 6 ]

8 голосов
/ 31 октября 2010

Лучший способ, который я нашел для достижения этой цели, - это распознаватель жестов. Неясно, хотите ли вы распознать события масштабирования самостоятельно или просто определить, когда пользователь выполняет масштабирование / панорамирование.

Мне не нужно обнаруживать панорамирование или масштабирование карты - мне просто важно, чтобы пользователь указал пальцем где-нибудь в MKMapView. Если вам нужно обнаружить масштабирование или панорамирование со 100% отзывом и точностью, это может быть более сложным, чем это. Что нам действительно нужно, так это реализация MKMapView с открытым исходным кодом, поэтому мы можем добавить это к делегату, среди многих других функций.

Вот что я делаю: Реализация распознавателя жестов, который не может быть предотвращен и который не может предотвратить другие распознаватели жестов. Добавьте его в вид карты и работайте с соответствующими событиями касания по своему желанию.

Как обнаружить любой сигнал внутри MKMapView (без хитростей)

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

WildcardGestureRecognizer.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

WildcardGestureRecognizer.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
5 голосов
/ 05 сентября 2009

У меня была та же проблема - я хотел нарисовать масштаб карты поверх вида карты. Для этого мне пришлось перехватить сенсорные события, а затем отправить их обратно в представление карты. К сожалению, когда MKMapView не является исходным приемником событий, некоторые плавные анимации панорамирования и масштабирования больше не работают.

Однако я нашел решение этой проблемы - немного странно, но работает: 1. Я поместил свой MapScales UIView поверх MKMapView и отключил получение событий в нем, чтобы базовый MKMapView получал события по умолчанию. 2. У меня есть подкласс UIWindow с классом MyMainWindow, и в нем я переопределил метод:

- (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:)

2 голосов
/ 16 сентября 2010
#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

Этот код обнаруживает касания, а также масштабирование.

1 голос
/ 09 мая 2010

Чтобы расширить ответ @ 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
1 голос
/ 19 августа 2009

Попробуйте

[super touchesEnded:touches withEvent:event];

вместо

[map touchesEnded:touches withEvent:event];

И применить эту идею ко всем методам сенсорных событий. Таким образом, касания должны пройти по цепочке респондента, и мир будет восстановлен.

0 голосов
/ 14 июля 2009

MKMapView не отвечает на сенсорные методы, перечисленные выше ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...