Como interceptar eventos de toque em objetos MKMapView ou UIWebView?

96

Não tenho certeza do que estou fazendo de errado, mas tento ouvir o toque em um MKMapViewobjeto. Eu criei uma subclasse criando a seguinte classe:

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>

@interface MapViewWithTouches : MKMapView {

}

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *) event;   

@end

E a implementação:

#import "MapViewWithTouches.h"
@implementation MapViewWithTouches

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *) event {

    NSLog(@"hello");
    //[super touchesBegan:touches   withEvent:event];

}
@end

Mas parece que quando uso esta classe, não vejo nada no console:

MapViewWithTouches *mapView = [[MapViewWithTouches alloc] initWithFrame:self.view.frame];
[self.view insertSubview:mapView atIndex:0];

Alguma ideia do que estou fazendo de errado?

Martin
fonte

Respostas:

147

A melhor maneira que encontrei de fazer isso é com um Reconhecedor de gestos. Outras maneiras envolvem muita programação hackeada que duplica imperfeitamente o código da Apple, especialmente no caso do multitoque.

Aqui está o que eu faço: implementar um reconhecedor de gestos que não pode ser evitado e que não pode impedir outros reconhecedores de gestos. Adicione-o à visualização do mapa e, em seguida, use os toquesBegan, toquesMovidos, etc. de gestoRecognizer, conforme desejar.

Como detectar qualquer toque dentro de um MKMapView (sem truques)

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

SWIFT 3

let tapInterceptor = WildCardGestureRecognizer(target: nil, action: nil)
tapInterceptor.touchesBeganCallback = {
    _, _ in
    self.lockedOnUserLocation = false
}
mapView.addGestureRecognizer(tapInterceptor)

WildCardGestureRecognizer.swift

import UIKit.UIGestureRecognizerSubclass

class WildCardGestureRecognizer: UIGestureRecognizer {

    var touchesBeganCallback: ((Set<UITouch>, UIEvent) -> Void)?

    override init(target: Any?, action: Selector?) {
        super.init(target: target, action: action)
        self.cancelsTouchesInView = false
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesBegan(touches, with: event)
        touchesBeganCallback?(touches, event)
    }

    override func canPrevent(_ preventedGestureRecognizer: UIGestureRecognizer) -> Bool {
        return false
    }

    override func canBePrevented(by preventingGestureRecognizer: UIGestureRecognizer) -> Bool {
        return false
    }
}
gonzojive
fonte
3
para que serve "lockedOnUserLocation"?
jowie de
essa é uma variável estranha específica ao meu aplicativo. ele controla se o sistema deve centralizar automaticamente o mapa no local atual
gonzojive
Esta é a solução perfeita. Preciso de um esclarecimento: No método "- (void) touchesBegan: (NSSet *) toca withEvent: (UIEvent *) event", qual é o propósito de usar o código: if (touchesBeganCallback) touchesBeganCallback (toca, evento);
Satyam
1
Isso funciona muito bem na maior parte, mas encontrei um problema com isso. Se o HTML em sua visualização da web contiver uma videotag HTML5 com controles, o reconhecedor de gestos impedirá que o usuário seja capaz de usar os controles. Tenho procurado uma solução alternativa para isso, mas ainda não encontrei uma.
Bryan Irace,
Obrigado por compartilhar. Por que não existe um método de delegado adequado para rastrear as interações do usuário com uma visualização de mapa está além da minha compreensão, mas funciona bem.
Justin Driscoll
29

Depois de um dia de pizzas, gritos, finalmente encontrei a solução! Muito legal!

Peter, eu usei seu truque acima e o ajustei um pouco para finalmente ter uma solução que funcione perfeitamente com MKMapView e deve funcionar também com UIWebView

MKTouchAppDelegate.h

#import <UIKit/UIKit.h>
@class UIViewTouch;
@class MKMapView;

@interface MKTouchAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
    UIViewTouch *viewTouch;
    MKMapView *mapView;
}
@property (nonatomic, retain) UIViewTouch *viewTouch;
@property (nonatomic, retain) MKMapView *mapView;
@property (nonatomic, retain) IBOutlet UIWindow *window;

@end

MKTouchAppDelegate.m

#import "MKTouchAppDelegate.h"
#import "UIViewTouch.h"
#import <MapKit/MapKit.h>

@implementation MKTouchAppDelegate

@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];
    [window makeKeyAndVisible];


}


- (void)dealloc {
    [window release];
    [super dealloc];
}


@end

UIViewTouch.h

#import <UIKit/UIKit.h>
@class UIView;

@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

UIViewTouch.m

#import "UIViewTouch.h"
#import <MapKit/MapKit.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");
    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

Espero que ajude alguns de vocês!

Felicidades

Martin
fonte
14
Agradável. Pequena sugestão: você deve evitar nomear suas próprias classes com um prefixo de IU. A Apple reserva / desencoraja o uso de NS ou UI como prefixo de classe, porque eles podem acabar entrando em conflito com uma classe Apple (mesmo se for uma classe privada).
Daniel Dickison
Ei Daniel, Você está perfeitamente certo, eu também pensei isso! Para completar minha resposta acima, deixe-me adicionar um pequeno aviso: Meu exemplo assume que há apenas um objeto viewTouched, que está consumindo todos os eventos. Mas isso não é verdade. Você pode ter algumas anotações no topo do seu mapa e então meu código não funciona mais. Para funcionar 100%, você precisa lembrar para cada hitTest a visualização associada a esse evento específico (e eventualmente liberá-la quando touchesEnded ou touchesCancelled for acionado para que você não precise controlar os eventos concluídos ...).
Martin
1
Código muito útil, obrigado Martin! Eu queria saber se você tentou aplicar zoom no mapa depois de implementar isso. Para mim, quando comecei a trabalhar usando basicamente o mesmo código que você usou acima, tudo parecia funcionar, exceto apertar o zoom do mapa. Alguém tem alguma ideia?
Adam Alexander
Ei Adam, eu também tenho essa limitação e realmente não entendo o porquê! Isso é realmente irritante. Se você encontrar uma solução, me avise! Thx
Martin
Ok, votei neste porque inicialmente pareceu resolver meu problema. CONTUDO...! Não consigo fazer o multi-touch funcionar. Ou seja, embora eu passe diretamente o touchesBegan e o touchesMoved para viewTouched (faço minha interceptação no touchesEnded), não consigo ampliar o mapa com gestos de pinça. (Continuação ...)
Olie
24
UITapGestureRecognizer *tgr = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleGesture:)];   
tgr.numberOfTapsRequired = 2;
tgr.numberOfTouchesRequired = 1;
[mapView addGestureRecognizer:tgr];
[tgr release];


- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer
{
    if (gestureRecognizer.state != UIGestureRecognizerStateEnded)
        return;

    CGPoint touchPoint = [gestureRecognizer locationInView:mapView];
    CLLocationCoordinate2D touchMapCoordinate = [mapView convertPoint:touchPoint toCoordinateFromView:mapView];

    //.............
}
Govind
fonte
3
Não sei por que essa não é a melhor resposta. Parece funcionar perfeitamente e é muito mais simples.
elsurudo
12

Para um MKMapView, a verdadeira solução de trabalho é o reconhecimento de gestos!

Eu Queria parar de atualizar o centro do mapa na minha localização quando arrasto o mapa ou aperto para aumentar o zoom.

Portanto, crie e adicione seu reconhecedor de gestos ao mapView:

- (void)viewDidLoad {

    ...

    // Add gesture recognizer for map hoding
    UILongPressGestureRecognizer *longPressGesture = [[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPressAndPinchGesture:)] autorelease];
    longPressGesture.delegate = self;
    longPressGesture.minimumPressDuration = 0;  // In order to detect the map touching directly (Default was 0.5)
    [self.mapView addGestureRecognizer:longPressGesture];

    // Add gesture recognizer for map pinching
    UIPinchGestureRecognizer *pinchGesture = [[[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPressAndPinchGesture:)] autorelease];
    pinchGesture.delegate = self;
    [self.mapView addGestureRecognizer:pinchGesture];

    // Add gesture recognizer for map dragging
    UIPanGestureRecognizer *panGesture = [[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)] autorelease];
    panGesture.delegate = self;
    panGesture.maximumNumberOfTouches = 1;  // In order to discard dragging when pinching
    [self.mapView addGestureRecognizer:panGesture];
}

Consulte a Referência de classe UIGestureRecognizer para ver todos os reconhecedores de gestos disponíveis.

Como definimos o delegado para self, temos que implementar o protocolo UIGestureRecognizerDelegate:

typedef enum {
    MapModeStateFree,                    // Map is free
    MapModeStateGeolocalised,            // Map centred on our location
    MapModeStateGeolocalisedWithHeading  // Map centred on our location and oriented with the compass
} MapModeState;

@interface MapViewController : UIViewController <CLLocationManagerDelegate, UIGestureRecognizerDelegate> {
    MapModeState mapMode;
}

@property (nonatomic, retain) IBOutlet MKMapView *mapView;
...

E substituir o método gestoRecognizer: gestRecognizer shouldRecognizeSimultaneousWithGestureRecognizer: para permitir reconhecer vários gestos simultaneamente, se entendi direito:

// Allow to recognize multiple gestures simultaneously (Implementation of the protocole UIGestureRecognizerDelegate)
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    return YES;
}

Agora escreva os métodos que serão chamados por nossos reconhecedores de gestos:

// On map holding or pinching pause localise and heading
- (void)handleLongPressAndPinchGesture:(UIGestureRecognizer *)sender {
    // Stop to localise and/or heading
    if (sender.state == UIGestureRecognizerStateBegan && mapMode != MapModeStateFree) {
        [locationManager stopUpdatingLocation];
        if (mapMode == MapModeStateGeolocalisedWithHeading) [locationManager stopUpdatingHeading];
    }
    // Restart to localise and/or heading
    if (sender.state == UIGestureRecognizerStateEnded && mapMode != MapModeStateFree) {
        [locationManager startUpdatingLocation];
        if (mapMode == MapModeStateGeolocalisedWithHeading) [locationManager startUpdatingHeading];
    }
}

// On dragging gesture put map in free mode
- (void)handlePanGesture:(UIGestureRecognizer *)sender {
    if (sender.state == UIGestureRecognizerStateBegan && mapMode != MapModeStateFree) [self setMapInFreeModePushedBy:sender];
}
Joan
fonte
Esta solução é perfeita! Algumas rapidinhas aqui: Se você quiser interceptar quando o usuário terminar de fazer qualquer ação usando isso, deve ser suficiente - (void) handleLongPressAndPinchGesture: (UIGestureRecognizer *) sender {if (sender.state == UIGestureRecognizerStateEnded) {NSLog (@ "handleLongPressPinchGestureAnded) ; }}
Alejandro Luengo
Também não se esqueça de adicionar o delegado <UIGestureRecognizerDelegate>
Alejandro Luengo
6

Caso alguém esteja tentando fazer o mesmo como eu: eu queria criar uma anotação no ponto onde o usuário toca. Para isso usei a UITapGestureRecognizersolução:

UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTapOnMap:)];
[self.mapView addGestureRecognizer:tapGestureRecognizer];
[tapGestureRecognizer setDelegate:self];

- (void)didTapOnMap:(UITapGestureRecognizer *)gestureRecognizer
{
    CGPoint point = [gestureRecognizer locationInView:self.mapView];
    CLLocationCoordinate2D coordinate = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
    .......
}

No entanto, didTapOnMap:também foi chamado quando toquei na anotação e uma nova seria criada. A solução é implementar UIGestureRecognizerDelegate:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if ([touch.view isKindOfClass:[MKAnnotationView class]])
    {
        return NO;
    }
    return YES;
}
jimpic
fonte
Esta é uma otima soluçao ! Mas não está funcionando se você usar uma visualização personalizada como MKAnnotation. Nesse caso, você pode ter outra subvisualização de anotação acionando o reconhecedor de gestos. Tive que verificar recursivamente o superview do touch.view para encontrar um potencial MKAnnotationView
KIDdAe
3

Provavelmente, você precisará sobrepor uma visualização transparente para captar os toques, da mesma forma que costuma ser feito com os controles baseados em UIWebView. O Map View já faz um monte de coisas especiais com um toque para permitir que o mapa seja movido, centralizado, ampliado, etc ... para que as mensagens não borbulhem no seu aplicativo.

Posso pensar em duas outras opções (NÃO TESTADAS):

1) Renuncie o primeiro a responder via IB e defina-o como "Proprietário do arquivo" para permitir que o proprietário do arquivo responda aos toques. Tenho dúvidas de que isso funcionará porque MKMapView estende NSObject, não UIView e, como resultado, os eventos de toque ainda podem não ser propagados para você.

2) Se você deseja capturar quando o estado do mapa muda (como em um zoom), apenas implemente o protocolo MKMapViewDelegate para ouvir eventos específicos. Meu palpite é que essa é sua melhor chance de capturar alguma interação facilmente (exceto implementar a visão transparente sobre o mapa). Não se esqueça de definir o View Controller que hospeda o MKMapView como o delegado do mapa ( map.delegate = self).

Boa sorte.

MystikSpiral
fonte
MKMapView definitivamente subclasses UIView.
Daniel Dickison
2

Eu não experimentei, mas há uma boa chance do MapKit ser baseado em um cluster de classes e, portanto, subclassificá-lo é difícil e ineficaz.

Eu sugiro fazer o MapKit view uma subvisão de uma visão customizada, que deve permitir que você intercepte eventos de toque antes que eles cheguem.

Grahamparks
fonte
Hello Graham! Obrigado pela ajuda! Se eu fizer uma visão superpersonalizada como a que você sugeriu, como poderia encaminhar eventos para o MKMapView? Qualquer ideia?
Martin
2

Então, depois de meio dia mexendo nisso, descobri o seguinte:

  1. Como todo mundo descobriu, beliscar não funciona. Tentei criar uma subclasse de MKMapView e o método descrito acima (interceptá-lo). E o resultado é o mesmo.
  2. Nos vídeos do iPhone de Stanford, um cara da Apple diz que muitas das coisas do UIKit causarão muitos erros se você "transferir" as solicitações de toque (também conhecidas como os dois métodos descritos acima), e você provavelmente não fará com que funcione.

  3. A SOLUÇÃO : é descrita aqui: Interceptando / Hijacking iPhone Touch Events para MKMapView . Basicamente, você "captura" o evento antes que qualquer respondente o receba e o interpreta ali.

thuang513
fonte
2

Em Swift 3.0

import UIKit
import MapKit

class CoordinatesPickerViewController: UIViewController {

    @IBOutlet var mapView: MKMapView!
    override func viewDidLoad() {
        super.viewDidLoad()

        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(clickOnMap))
        mapView.addGestureRecognizer(tapGestureRecognizer)
    }

    @objc func clickOnMap(_ sender: UITapGestureRecognizer) {

        if sender.state != UIGestureRecognizerState.ended { return }
        let touchLocation = sender.location(in: mapView)
        let locationCoordinate = mapView.convert(touchLocation, toCoordinateFrom: mapView)
        print("Tapped at lat: \(locationCoordinate.latitude) long: \(locationCoordinate.longitude)")

    }

}
Francisco castro
fonte
0

Faça do MKMapView uma subvisão de uma visão personalizada e implemente

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event

na visualização personalizada para retornar a si mesmo em vez da subvisualização.

Peter N Lewis
fonte
Olá Pedro, Obrigado pela sua resposta! Mas eu acho que fazendo isso, o MKMapView pode não ser capaz de obter nenhum evento de toque, não é? Estou procurando uma maneira de apenas capturar o evento e, em seguida, encaminhá-lo para o MKMapView.
Martin
0

Obrigado pela pizza e gritos - você me economizou muito tempo.

habilitado para multipleto funcionará esporadicamente.

viewTouch.multipleTouchEnabled = TRUE;

No final, mudei as visualizações quando precisei capturar o toque (ponto diferente no tempo do que a necessidade de pinchzooms):

    [mapView removeFromSuperview];
    [viewTouch addSubview:mapView];
    [self.view insertSubview:viewTouch atIndex:0];
BankStrong
fonte
mas não funciona com zoom ao vivo. Ele também parece sempre diminuir o zoom.
Rog
0

Percebi que você pode rastrear o número e a localização dos toques e obter a localização de cada um em uma visualização:

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"Touch Moved %d", [[event allTouches] count]);

 NSEnumerator *enumerator = [touches objectEnumerator];
 id value;

 while ((value = [enumerator nextObject])) {
  NSLog(@"touch description %f", [value locationInView:mapView].x);
 }
    [viewTouched touchesMoved:touches withEvent:event];
}

Alguém mais tentou usar esses valores para atualizar o nível de zoom do mapa? Seria uma questão de registrar as posições de largada e depois as localizações de chegada, calculando a diferença relativa e atualizando o mapa.

Estou brincando com o código básico fornecido por Martin e parece que vai funcionar ...

Dan Donaldson
fonte
0

Aqui está o que eu juntei, que permite zooms de pinça no simulador (não tentei em um iPhone real), mas acho que seria bom:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"Touch Began %d", [touches count]);
 reportTrackingPoints = NO;
 startTrackingPoints = YES;
    [viewTouched touchesBegan:touches withEvent:event];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
 if ([[event allTouches] count] == 2) {
  reportTrackingPoints = YES;
  if (startTrackingPoints == YES) {
   BOOL setA = NO;
   NSEnumerator *enumerator = [[event allTouches] objectEnumerator];
   id value;
   while ((value = [enumerator nextObject])) {
    if (! setA) {
     startPointA = [value locationInView:mapView];
     setA = YES;
    } else {
     startPointB = [value locationInView:mapView];
    }
   }
   startTrackingPoints = NO;
  } else {
   BOOL setA = NO;
   NSEnumerator *enumerator = [[event allTouches] objectEnumerator];
   id value;
   while ((value = [enumerator nextObject])) {
    if (! setA) {
     endPointA = [value locationInView:mapView];
     setA = YES;
    } else {
     endPointB = [value locationInView:mapView];
    }
   }
  }
 }
 //NSLog(@"Touch Moved %d", [[event allTouches] count]);
    [viewTouched touchesMoved:touches withEvent:event];
}

- (void) updateMapFromTrackingPoints {
 float startLenA = (startPointA.x - startPointB.x);
 float startLenB = (startPointA.y - startPointB.y);
 float len1 = sqrt((startLenA * startLenA) + (startLenB * startLenB));
 float endLenA = (endPointA.x - endPointB.x);
 float endLenB = (endPointA.y - endPointB.y);
 float len2 = sqrt((endLenA * endLenA) + (endLenB * endLenB));
 MKCoordinateRegion region = mapView.region;
 region.span.latitudeDelta = region.span.latitudeDelta * len1/len2;
 region.span.longitudeDelta = region.span.longitudeDelta * len1/len2;
 [mapView setRegion:region animated:YES];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
 if (reportTrackingPoints) {
  [self updateMapFromTrackingPoints];
  reportTrackingPoints = NO;
 }


    [viewTouched touchesEnded:touches withEvent:event];
}

A ideia principal é que, se o usuário estiver usando dois dedos, você acompanhe os valores. Eu registro os pontos inicial e final nos pontos iniciais A e B. Então eu registro os pontos de rastreamento atuais e, quando terminar, no touchEnded, posso chamar uma rotina para calcular os comprimentos relativos da linha entre os pontos com os quais começo , e a linha entre o ponto I termina usando simples hipotenusa calc. A proporção entre eles é a quantidade de zoom: eu multiplico a extensão da região por essa quantidade.

Espero que seja útil para alguém.

Dan Donaldson
fonte
0

Eu peguei a ideia de uma visão transparente "sobreposta", da resposta de MystikSpiral, e funcionou perfeitamente para o que eu estava tentando alcançar; solução rápida e limpa.

Resumindo, eu tinha um UITableViewCell customizado (projetado em IB) com um MKMapView no lado esquerdo e alguns UILabels à direita. Eu queria fazer a célula personalizada para que você pudesse tocá-la em qualquer lugar e isso empurraria um novo controlador de visualização. No entanto, tocar o mapa não passou "para cima" no UITableViewCell até que eu simplesmente adicionei um UIView do mesmo tamanho que a visualização do mapa bem em cima dele (em IB) e tornei seu fundo a 'cor clara' no código ( não acho que você pode definir clearColor em IB ??):

dummyView.backgroundColor = [UIColor clearColor];

Achei que poderia ajudar outra pessoa; certamente se você deseja obter o mesmo comportamento para uma célula de exibição de tabela.

petert
fonte
"No entanto, tocar o mapa não passa o retoque para o UITableViewCell até que eu simplesmente adicione um UIView do mesmo tamanho que a visualização do mapa logo acima dele" Isso não é verdade. O mapa está processando toques porque tem suas próprias interações do usuário, como rolagem etc. Se você quiser detectar o pensamento na célula em vez de interagir com o mapa, basta definir map.isUserInteractionEnabled = false. Você pode então usar didSelectRowAtIndexPath na tabela ver delegado.
BROK3N S0UL