Bagaimana cara mencegat kejadian sentuhan pada objek MKMapView atau UIWebView?

96

Saya tidak yakin apa yang saya lakukan salah tetapi saya mencoba untuk menangkap sentuhan pada suatu MKMapViewobjek. Saya membuat subkelasnya dengan membuat kelas berikut:

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

@interface MapViewWithTouches : MKMapView {

}

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

@end

Dan implementasinya:

#import "MapViewWithTouches.h"
@implementation MapViewWithTouches

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

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

}
@end

Tapi sepertinya ketika saya menggunakan kelas ini, saya tidak melihat apa-apa di Konsol:

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

Tahu apa yang saya lakukan salah?

Martin
sumber

Jawaban:

147

Cara terbaik yang saya temukan untuk mencapai ini adalah dengan Pengenal Gerakan. Cara lain ternyata melibatkan banyak program hackish yang secara tidak sempurna menduplikasi kode Apple, terutama dalam kasus multitouch.

Inilah yang saya lakukan: Menerapkan pengenal isyarat yang tidak dapat dicegah dan tidak dapat mencegah pengenal isyarat lainnya. Tambahkan ke tampilan peta, dan kemudian gunakan sentuhan gestureRecognizer'sBegan, touchesMoved, dll sesuai keinginan Anda.

Cara mendeteksi ketukan apa pun di dalam MKMapView (tanpa trik)

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.dll
sumber
3
untuk apa "lockOnUserLocation"?
jowie
itu adalah variabel asing khusus untuk aplikasi saya. itu melacak apakah sistem harus secara otomatis memusatkan peta di lokasi saat ini
gonzojive
Ini adalah solusi yang tepat. Saya butuh satu klarifikasi: Dalam metode "- (void) touchesBegan: (NSSet *) touches withEvent: (UIEvent *) event", apa tujuan penggunaan kode: if (touchesBeganCallback) touchesBeganCallback (touches, event);
Satyam
1
Ini berfungsi dengan baik untuk sebagian besar tetapi saya menemukan satu masalah dengannya. Jika HTML dalam tampilan web Anda berisi videotag HTML5 dengan kontrol, pengenal isyarat akan mencegah pengguna untuk dapat menggunakan kontrol tersebut. Saya telah mencari solusi untuk ini tetapi belum menemukannya.
Bryan Irace
Terima kasih sudah berbagi. Mengapa tidak ada metode delegasi yang cocok untuk melacak interaksi pengguna dengan tampilan peta berada di luar jangkauan saya, tetapi ini bekerja dengan baik.
Justin Driscoll
29

Setelah seharian makan pizza, teriakan, akhirnya saya menemukan solusinya! Sangat rapi!

Peter, saya menggunakan trik Anda di atas dan mengubahnya sedikit untuk akhirnya memiliki solusi yang bekerja sempurna dengan MKMapView dan juga harus bekerja dengan 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

Saya harap itu akan membantu beberapa dari Anda!

Bersulang

Martin
sumber
14
Bagus. Saran kecil: Anda harus menghindari penamaan kelas Anda sendiri dengan awalan UI. Apple mencadangkan / melarang penggunaan NS atau UI sebagai awalan kelas, karena ini mungkin akan berbenturan dengan kelas Apple (meskipun itu kelas privat).
Daniel Dickison
Hei Daniel, Anda benar sekali, saya juga berpikir begitu! Untuk melengkapi jawaban saya di atas, izinkan saya menambahkan sedikit peringatan: Contoh Saya menganggap hanya ada satu objek viewTouched, yang memakan semua kejadian. Tapi itu tidak benar. Anda dapat memiliki beberapa Anotasi di atas Peta Anda dan kemudian kode saya tidak berfungsi lagi. Untuk bekerja 100%, Anda perlu mengingat untuk setiap hitTest tampilan yang terkait dengan peristiwa tertentu (dan akhirnya melepaskannya saat touchesEnded atau touchesCancelled dipicu sehingga Anda tidak perlu melacak acara yang sudah selesai ...).
Martin
1
Kode yang sangat berguna, terima kasih Martin! Saya ingin tahu apakah Anda mencoba mencubit-zoom peta setelah menerapkan ini? Bagi saya, ketika saya membuatnya bekerja dengan menggunakan kode yang pada dasarnya sama yang Anda miliki di atas semuanya tampaknya berfungsi kecuali pinch zooming peta. Ada yang punya ide?
Adam Alexander
Hai Adam, saya juga memiliki batasan ini dan saya tidak begitu mengerti mengapa! Itu sangat menjengkelkan. Jika Anda menemukan solusi, beri tahu saya! Thx
Martin
Oke, saya memilih yang ini karena awalnya tampaknya menyelesaikan masalah saya. NAMUN...! Sepertinya saya tidak bisa menggunakan multi-touch untuk bekerja. Artinya, meskipun saya langsung mengoper touchesBegan dan touchesMoved to viewTouched (saya melakukan intersep pada touchesEnded), saya tidak dapat memperbesar peta dengan gerakan mencubit. (Lanjutan ...)
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
sumber
3
Saya tidak yakin mengapa ini bukan jawaban teratas. Tampaknya bekerja dengan sempurna, dan jauh lebih sederhana.
elsurudo
12

Untuk MKMapView, solusi yang berfungsi sebenarnya adalah dengan pengenalan gerakan!

Saya Saya ingin berhenti memperbarui pusat peta di lokasi saya ketika saya menyeret peta atau mencubit untuk memperbesar.

Jadi, buat dan tambahkan pengenal gerakan Anda ke 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];
}

Lihat Referensi Kelas UIGestureRecognizer untuk melihat semua pengenal gerakan yang tersedia.

Karena kita telah mendefinisikan delegasi untuk dirinya sendiri, kita harus menerapkan protocole 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;
...

Dan menimpa metode gestureRecognizer: gestureRecognizer shouldRecognizeSimoraryouslyWithGestureRecognizer: untuk memungkinkan mengenali beberapa gerakan secara bersamaan, jika saya mengerti benar:

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

Sekarang tulis metode yang akan dipanggil oleh pengenal isyarat kami:

// 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
sumber
Solusi ini sempurna! Beberapa quickies di sini: Jika Anda ingin mencegat saat pengguna berhenti melakukan tindakan apa pun menggunakan ini harus cukupt - (void) handleLongPressAndPinchGesture: (UIGestureRecognizer *) sender {if (sender.state == UIGestureRecognizerStateEnded) {NSLog (@ "handleLongPressAndPinchGesture Berakhir") ; }}
Alejandro Luengo
Juga jangan lupa untuk menambahkan delegasi <UIGestureRecognizerDelegate>
Alejandro Luengo
6

Untuk berjaga-jaga jika seseorang mencoba melakukan hal yang sama seperti saya: Saya ingin membuat anotasi pada titik di mana pengguna mengetuk. Untuk itu saya menggunakan UITapGestureRecognizersolusinya:

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

Namun, didTapOnMap:juga dipanggil ketika saya mengetuk anotasi dan yang baru akan dibuat. Solusinya adalah dengan menerapkan UIGestureRecognizerDelegate:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if ([touch.view isKindOfClass:[MKAnnotationView class]])
    {
        return NO;
    }
    return YES;
}
jimpic
sumber
Ini adalah solusi yang bagus! Tapi itu tidak berfungsi jika Anda menggunakan tampilan kustom sebagai MKAnnotation. Dalam kasus ini, Anda mungkin memiliki subview anotasi lain yang memicu pengenal isyarat. Saya harus secara rekursif memeriksa superview dari touch.view untuk menemukan potensi MKAnnotationView
KIDdAe
3

Anda mungkin perlu menghamparkan tampilan transparan untuk menangkap sentuhan seperti yang sering dilakukan dengan kontrol berbasis UIWebView. Tampilan Peta sudah melakukan banyak hal khusus dengan satu sentuhan untuk memungkinkan peta dipindahkan, dipusatkan, diperbesar, dll ... sehingga pesan tidak meluap ke aplikasi Anda.

Dua opsi (UNTESTED) lainnya yang dapat saya pikirkan:

1) Mundur responden pertama melalui IB dan setel ke "Pemilik File" untuk memungkinkan Pemilik file untuk menanggapi sentuhan. Saya meragukan bahwa ini akan berhasil karena MKMapView memperluas NSObject, bukan UIView dan akibatnya peristiwa sentuh masih mungkin tidak disebarluaskan kepada Anda.

2) Jika Anda ingin menjebak saat status Peta berubah (seperti pada zoom) cukup terapkan protokol MKMapViewDelegate untuk mendengarkan kejadian tertentu. Firasat saya adalah ini adalah bidikan terbaik Anda dalam menjebak beberapa interaksi dengan mudah (singkatnya menerapkan Tampilan transparan di atas Peta). Jangan lupa untuk mengatur View Controller yang menampung MKMapView sebagai delegasi peta (map.delegate = self ).

Semoga berhasil.

MystikSpiral
sumber
MKMapView pasti subclass UIView.
Daniel Dickison
2

Saya belum bereksperimen, tetapi ada kemungkinan besar MapKit berbasis di sekitar cluster kelas, dan oleh karena itu subclassing itu sulit dan tidak efektif.

Saya menyarankan membuat tampilan MapKit subview dari tampilan kustom, yang akan memungkinkan Anda untuk mencegat kejadian sentuh sebelum mereka mencapainya.

grahamparks
sumber
Halo Graham! Terima kasih untuk bantuannya! Jika saya membuat tampilan kustom super seperti yang Anda sarankan, bagaimana saya bisa meneruskan acara ke MKMapView? Ada ide?
Martin
2

Jadi setelah setengah hari mengotak-atik ini, saya menemukan yang berikut:

  1. Seperti yang ditemukan orang lain, mencubit tidak berhasil. Saya mencoba subclass MKMapView dan metode yang dijelaskan di atas (mencegatnya). Dan hasilnya sama saja.
  2. Dalam video iPhone Stanford, seorang pria dari Apple mengatakan bahwa banyak hal UIKit akan menyebabkan banyak kesalahan jika Anda "mentransfer" permintaan sentuh (alias dua metode yang dijelaskan di atas), dan Anda mungkin tidak akan membuatnya berfungsi.

  3. SOLUSI : dijelaskan di sini: Mencegah / Membajak Peristiwa Sentuh iPhone untuk MKMapView . Pada dasarnya Anda "menangkap" kejadian tersebut sebelum responden mana pun mendapatkannya, dan menafsirkannya di sana.

thuang513
sumber
2

Di 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
sumber
0

Jadikan MKMapView sebagai subview dari tampilan kustom dan implementasikan

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

di tampilan kustom untuk menampilkan diri sendiri, bukan subview.

Peter N Lewis
sumber
Halo Peter, Terima kasih atas jawaban Anda! Tapi saya pikir dengan melakukan itu, MKMapView mungkin tidak bisa mendapatkan event touche, bukan? Saya mencari cara untuk menangkap acara dan kemudian meneruskannya ke MKMapView.
Martin
0

Terima kasih untuk pizza dan teriakannya - Anda menghemat banyak waktu saya.

multipletouchenabled akan bekerja secara sporadis.

viewTouch.multipleTouchEnabled = TRUE;

Pada akhirnya, saya mengalihkan pandangan ketika saya perlu menangkap sentuhan (titik waktu yang berbeda daripada membutuhkan pinchzooms):

    [mapView removeFromSuperview];
    [viewTouch addSubview:mapView];
    [self.view insertSubview:viewTouch atIndex:0];
BankStrong
sumber
tetapi tidak berfungsi dengan zoom langsung. Itu juga tampaknya selalu memperkecil.
Rog
0

Saya perhatikan bahwa Anda dapat melacak jumlah dan lokasi sentuhan, dan mendapatkan lokasi masing-masing dalam tampilan:

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

Adakah orang lain yang mencoba menggunakan nilai-nilai ini untuk memperbarui tingkat zoom peta? Ini akan menjadi masalah mencatat posisi awal, dan kemudian lokasi selesai, menghitung perbedaan relatif dan memperbarui peta.

Saya bermain dengan kode dasar yang disediakan oleh Martin, dan ini sepertinya akan berhasil ...

Dan Donaldson
sumber
0

Inilah yang saya kumpulkan, yang memungkinkan pinch zooms di simulator (belum mencoba di iPhone asli), tapi saya pikir akan baik-baik saja:

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

Ide utamanya adalah jika pengguna menggunakan dua jari, Anda melacak nilainya. Saya mencatat titik awal dan akhir di titik awal A dan B. Kemudian saya mencatat titik pelacakan saat ini, dan setelah selesai, saat selesai, saya dapat memanggil rutinitas untuk menghitung panjang relatif garis antara titik yang saya mulai , dan garis antara titik yang saya akhiri dengan menggunakan kalkulasi miring sederhana. Rasio di antara keduanya adalah jumlah zoom: Saya mengalikan rentang wilayah dengan jumlah itu.

Semoga bermanfaat bagi seseorang.

Dan Donaldson
sumber
0

Saya mengambil ide tentang tampilan transparan "overlay", dari jawaban MystikSpiral, dan itu bekerja dengan sempurna untuk apa yang ingin saya capai; solusi cepat dan bersih.

Singkatnya, saya memiliki UITableViewCell kustom (dirancang dalam IB) dengan MKMapView di sisi kiri dan beberapa UILabel di kanan. Saya ingin membuat sel khusus sehingga Anda dapat menyentuhnya di mana saja dan ini akan mendorong pengontrol tampilan baru. Namun menyentuh peta tidak memberikan sentuhan 'ke atas' ke UITableViewCell sampai saya menambahkan UIView dengan ukuran yang sama seperti tampilan peta tepat di atasnya (dalam IB) dan menjadikannya latar belakang 'warna yang jelas' dalam kode ( jangan berpikir Anda dapat mengatur clearColor di IB ??):

dummyView.backgroundColor = [UIColor clearColor];

Pikir itu mungkin membantu orang lain; tentu saja jika Anda ingin mencapai perilaku yang sama untuk sel tampilan tabel.

petert
sumber
"Namun menyentuh peta tidak memberikan sentuhan 'atas' ke UITableViewCell sampai saya menambahkan UIView dengan ukuran yang sama dengan tampilan peta tepat di atasnya." Ini tidak benar. Peta sedang memproses sentuhan karena memiliki interaksi penggunanya sendiri seperti menggulir, dll. Jika Anda ingin mendeteksi olah pada sel alih-alih berinteraksi dengan peta, cukup setel map.isUserInteractionEnabled = false Anda kemudian dapat menggunakan didSelectRowAtIndexPath di tabel lihat delegasi.
BROK3N S0UL