Bir MKMapView veya UIWebView nesnelerindeki dokunma olaylarını nasıl kesebilirim?


96

Neyi yanlış yaptığımdan emin değilim ama bir MKMapViewnesneye dokunmaya çalışıyorum . Aşağıdaki sınıfı oluşturarak onu alt sınıflara ayırdım:

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

@interface MapViewWithTouches : MKMapView {

}

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

@end

Ve uygulama:

#import "MapViewWithTouches.h"
@implementation MapViewWithTouches

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

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

}
@end

Ama görünüşe göre bu sınıfı kullandığımda, Konsolda hiçbir şey görmüyorum:

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

Neyi yanlış yaptığım hakkında bir fikrin var mı?

Yanıtlar:


147

Bunu başarmanın bulduğum en iyi yolu bir Hareket Algılayıcı kullanmaktır. Diğer yollar, özellikle çoklu dokunma durumunda, Apple'ın kodunu kusurlu bir şekilde kopyalayan çok sayıda bilgisayar korsanlığı programlamayı içerir.

Yaptığım şey şu: Engellenemeyen ve diğer hareket tanıyıcıları engelleyemeyen bir hareket tanıyıcı uygulayın. Bunu harita görünümüne ekleyin ve ardından jestRecognizer'ın touchesBegan, touchesMoved, vb. Özelliklerini istediğiniz gibi kullanın.

Bir MKMapView içindeki herhangi bir dokunma nasıl tespit edilir (sans hileleri)

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

3
"lockedOnUserLocation" ne için?
jowie

bu, benim uygulamama özgü yabancı bir değişkendir. sistemin haritayı otomatik olarak geçerli konuma
ortalayıp ortalamayacağını izler

Bu mükemmel bir çözüm. Bir açıklamaya ihtiyacım var: "- (void) touchesBegan: (NSSet *) touches withEvent: (UIEvent *) event" yönteminde, kodu kullanmanın amacı nedir: if (touchesBeganCallback) touchesBeganCallback (touches, event);
Satyam

1
Bu çoğunlukla harika çalışıyor ama onunla bir sorun buldum. Web görünümünüzdeki HTML, videokontrollere sahip bir HTML5 etiketi içeriyorsa , hareket tanıyıcı, kullanıcının kontrolleri kullanmasını engeller. Bunun için bir çözüm arıyordum ama henüz bulamadım.
Bryan Irace

Paylaşım için teşekkürler. Bir harita görünümüyle kullanıcı etkileşimlerini izlemek için neden uygun bir temsilci yönteminin olmaması benim dışımda ama bu iyi çalışıyor.
Justin Driscoll

29

Pizzalarla, çığlıklarla geçen bir günün ardından nihayet çözümü buldum! Çok temiz!

Peter, senin numaranı yukarıda kullandım ve sonunda MKMapView ile mükemmel çalışan ve UIWebView ile de çalışması gereken bir çözüme sahip olmak için biraz değiştirdim.

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

Umarım bu bazılarınıza yardımcı olur!

Şerefe


14
Güzel. Küçük öneri: Kendi sınıflarınızı bir UI öneki ile adlandırmaktan kaçınmalısınız. Apple, NS veya UI'yi sınıf öneki olarak kullanmayı reddeder / vazgeçirir, çünkü bunlar bir Apple sınıfı ile çakışabilir (özel bir sınıf olsa bile).
Daniel Dickison

Hey Daniel, kesinlikle haklısın, ben de öyle düşündüm! Yukarıdaki cevabımı tamamlamak için, küçük bir uyarı eklememe izin verin: Örneğim, tüm olayları tüketen yalnızca bir nesne viewTouched olduğunu varsayar. Ama bu doğru değil. Haritanızın üzerinde bazı Ek Açıklamalar olabilir ve ardından kodum artık çalışmaz. % 100 çalışmak için, her hitTest için o belirli olayla ilişkili görünümü hatırlamanız gerekir (ve sonunda dokunduğunda veya dokunulduğunda iptal edildiğinde serbest bırakın, böylece bitmiş olayları takip etmenize gerek kalmaz ...).
Martin

1
Çok kullanışlı kod, teşekkürler Martin! Bunu uyguladıktan sonra haritayı sıkıştırarak yakınlaştırmayı denediniz mi? Benim için, temelde sahip olduğunuz aynı kodu kullanarak çalıştırdığımda, haritayı yakınlaştırmak dışında her şey işe yaradı. Herhangi bir fikri olan var mı?
Adam Alexander

Hey Adam, bende de bu sınırlama var ve nedenini gerçekten anlamıyorum! Bu gerçekten can sıkıcı. Bir çözüm bulursanız bana bildirin! Thx
Martin

Tamam, bunu oyladım çünkü başlangıçta sorunumu çözmüş gibi görünüyordu. ANCAK...! Çoklu dokunuşla çalışamıyorum. Yani, touchesBegan ve touchesMoved to viewTouched'ı doğrudan geçsem de (durdurma işlemimi Bitti dokunuşlarında yapıyorum), haritayı kıstırma hareketleriyle yakınlaştıramıyorum. (Devamı ...)
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];

    //.............
}

3
Bunun neden en iyi cevap olmadığından emin değilim. Mükemmel çalışıyor gibi görünüyor ve çok daha basit.
elsurudo

12

Bir MKMapView için gerçek çalışma çözümü jest tanıma ile olur!

Ben haritayı sürüklediğimde veya yakınlaştırmak için kıstırdığımda haritanın merkezini konumumda güncellemeyi durdurmak istedim.

Bu nedenle, hareket tanıyıcınızı oluşturun ve mapView'e ekleyin:

- (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];
}

Kullanılabilir tüm hareket tanıyıcıları görmek için UIGestureRecognizer Sınıf Referansına bakın.

Temsilciyi kendimize tanımladığımız için, UIGestureRecognizerDelegate protokolünü uygulamalıyız:

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

Ayrıca, doğru anladıysam, birden fazla hareketi aynı anda tanımaya izin vermek için, methode jestRecognizer: jestRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer'ı geçersiz kılın:

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

Şimdi hareket tanıyıcılarımız tarafından çağrılacak yöntemleri yazın:

// 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];
}

Bu çözüm mükemmel! Burada bazı hızlı bilgiler: Kullanıcı bunu kullanarak herhangi bir işlem yapmayı bitirdiğinde müdahale etmek istiyorsanız - (void) handleLongPressAndPinchGesture: (UIGestureRecognizer *) gönderen {if (sender.state == UIGestureRecognizerStateEnded) {NSLog (@ "handleLongPressAndPinchGesture Ended") ; }}
Alejandro Luengo

Ayrıca <UIGestureRecognizerDelegate> temsilcisini de eklemeyi unutmayın
Alejandro Luengo

6

Biri benim gibi aynı şeyi yapmaya çalışırsa: Kullanıcının dokunduğu noktada bir açıklama oluşturmak istedim. Bunun için UITapGestureRecognizerçözümü kullandım :

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];
    .......
}

Ancak, didTapOnMap:ek açıklamaya dokunduğumda da çağrıldı ve yeni bir tane oluşturulacaktı. Çözüm, aşağıdakileri uygulamaktır UIGestureRecognizerDelegate:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if ([touch.view isKindOfClass:[MKAnnotationView class]])
    {
        return NO;
    }
    return YES;
}

Bu harika bir çözüm! Ancak özel bir görünüm kullanırsanız çalışmıyor MKAnnotation. Bu durumda, hareket tanıyıcıyı tetikleyen başka bir ek açıklamanın alt görünümüne sahip olabilirsiniz. Potansiyel bir MKAnnotationView
KIDdAe

3

UIWebView tabanlı kontrollerde çok sık yapıldığı gibi dokunuşları yakalamak için muhtemelen şeffaf bir görünümü kaplamanız gerekecektir. Harita Görünümü, haritanın hareket ettirilmesine, ortalanmasına, yakınlaştırılmasına vb. İzin vermek için zaten bir dokunuşla bir dizi özel şey yapıyor.

Aklıma gelen diğer iki (TEST EDİLMEMİŞ) seçenek:

1) IB aracılığıyla ilk yanıtlayanı istifa edin ve dosyanın Sahibinin dokunuşlara yanıt vermesine izin vermek için "Dosyanın Sahibi" olarak ayarlayın. Bunun işe yarayacağından şüpheliyim, çünkü MKMapView UIView değil NSObject'i genişletiyor ve sonuç olarak dokunma olayları hala size yayılamayabilir.

2) Harita durumu değiştiğinde (yakınlaştırma gibi) tuzağa düşürmek istiyorsanız, belirli olayları dinlemek için MKMapViewDelegate protokolünü uygulayın. Benim önsezim, bazı etkileşimleri kolayca yakalamak için en iyi şansın budur (Harita üzerinde şeffaf Görünümü uygulamaktan kısadır). MKMapView'i barındıran Görünüm Kontrolörünü haritanın temsilcisi ( map.delegate = self) olarak ayarlamayı unutmayın .

İyi şanslar.


MKMapView kesinlikle UIView alt sınıflarıdır.
Daniel Dickison

2

Deney yapmadım, ancak MapKit'in bir sınıf kümesine dayandığı için iyi bir şans var ve bu nedenle alt sınıflara ayırmak zor ve etkisizdir.

MapKit görünümünü, dokunma olaylarına ulaşmadan önce müdahale etmenize izin veren özel bir görünümün bir alt görünümü oluşturmanızı öneririm.


Merhaba Graham! Yardımın için teşekkürler! Önerdiğiniz gibi süper özel bir görünüm yaparsam, olayları MKMapView'a nasıl iletebilirim? Herhangi bir fikir?
Martin

2

Yarım gün bununla uğraştıktan sonra şunu buldum:

  1. Herkesin bulduğu gibi, çimdikleme çalışmıyor. Hem alt sınıflandırma MKMapView'i hem de yukarıda açıklanan yöntemi denedim (yakalama). Ve sonuç aynı.
  2. Stanford iPhone videolarında, Apple'dan bir adam, dokunma isteklerini (diğer bir deyişle yukarıda açıklanan iki yöntem) "aktarırsanız" UIKit olaylarının birçoğunun birçok hataya neden olacağını ve muhtemelen işe yaramayacağını söylüyor.

  3. ÇÖZÜM : burada açıklanmaktadır: MKMapView için iPhone Touch Olaylarını Yakalama / Ele Geçirme . Temel olarak, herhangi bir yanıt veren onu almadan önce olayı "yakalar" ve orada yorumlarsınız.


2

Swift 3.0'da

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)")

    }

}

0

MKMapView'i özel bir görünümün bir alt görünümü yapın ve uygulayın

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

özel görünümde alt görünüm yerine kendini döndürmek için.


Merhaba Peter, Cevabınız için teşekkürler! Ama bence bunu yaparak, MKMapView herhangi bir touche olayını alamayabilir, değil mi? Sadece olayı yakalamanın ve ardından bunu MKMapView'a iletmenin bir yolunu arıyorum.
Martin

0

Pizza ve çığlıklar için teşekkürler - bana çok zaman kazandırdın.

multipletouchenabled, düzensiz çalışacaktır.

viewTouch.multipleTouchEnabled = TRUE;

Sonunda, dokunuşu yakalamam gerektiğinde görünümleri değiştirdim (zaman içinde kıskaçlara ihtiyaç duymaktan farklı bir nokta):

    [mapView removeFromSuperview];
    [viewTouch addSubview:mapView];
    [self.view insertSubview:viewTouch atIndex:0];

ancak canlı yakınlaştırmayla çalışmaz. Ayrıca her zaman uzaklaşıyor gibi görünüyor.
Rog

0

Dokunuşların sayısını ve konumunu takip edebileceğinizi ve her birinin konumunu bir görünümde alabileceğinizi fark ettim:

- (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];
}

Haritanın yakınlaştırma seviyesini güncellemek için başka biri bu değerleri kullanmayı denedi mi? Bu, başlangıç ​​konumlarının ve ardından bitiş konumlarının kaydedilmesi, göreceli farkın hesaplanması ve haritanın güncellenmesi meselesidir.

Martin tarafından sağlanan temel kodla oynuyorum ve bu işe yarayacak gibi görünüyor ...


0

Simülatörde çimdik yakınlaştırmaya izin veren (gerçek bir iPhone'da denemedim) bir araya getirdiğim şey şöyle, ancak iyi olacağını düşünüyorum:

- (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];
}

Ana fikir, eğer kullanıcı iki parmağını kullanıyorsa, değerleri takip etmenizdir. Başlangıç ​​ve bitiş noktalarını başlangıç ​​noktaları A ve B'ye kaydederim.Sonra mevcut izleme noktalarını kaydederim ve bitirdiğimde Bitti dokunuşlarında, başladığım noktalar arasındaki çizginin göreceli uzunluklarını hesaplamak için bir rutin çağırabilirim. ve basit hipotenüs hesaplamasını kullanarak bitirdiğim nokta arasındaki çizgi. Aralarındaki oran yakınlaştırma miktarıdır: Bölge aralığını bu miktarla çarpıyorum.

Umarım birisi için yararlıdır.


0

MystikSpiral'in cevabından bir "örtüşme" şeffaf görüş fikrini aldım ve başarmaya çalıştığım şey için mükemmel çalıştı; hızlı ve temiz çözüm.

Kısacası, sol tarafta bir MKMapView ve sağ tarafta bazı UILabels bulunan özel bir UITableViewCell (IB'de tasarlanmış) vardı. Özel hücreyi istediğiniz yere dokunabilmeniz için yapmak istedim ve bu yeni bir görüntü denetleyicisini zorlayacaktır. Bununla birlikte, haritaya dokunmak, UITableViewCell'e 'yukarı' rötuşları, harita görünümüyle aynı boyutta bir UIV görünümünü hemen üstüne (IB'de) ekleyip arka planını kodda 'açık renk' yapana kadar geçmedi ( IB'de clearColor ayarlayabileceğinizi düşünmüyor musunuz ??):

dummyView.backgroundColor = [UIColor clearColor];

Başkasına yardımcı olabileceğini düşündüm; kesinlikle bir tablo görüntüleme hücresi için aynı davranışı elde etmek istiyorsanız.


"Bununla birlikte, haritaya dokunmak UITableViewCell'e 'yukarı' rötuşları, sadece harita görünümüyle aynı boyutta bir UIV görünümünü hemen üstüne ekleyene kadar geçmedi" Bu doğru değil. Harita, kaydırma vb. Gibi kendi kullanıcı etkileşimlerine sahip olduğu için dokunmaları işliyor. Haritayla etkileşim kurmak yerine hücredeki düşünceleri algılamak istiyorsanız, sadece map.isUserInteractionEnabled = false değerini ayarlayın Daha sonra tablodaki didSelectRowAtIndexPath'i kullanabilirsiniz. temsilciyi görüntüle.
BROK3N S0UL
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.