Wie kann ich Berührungsereignisse an MKMapView- oder UIWebView-Objekten abfangen?

96

Ich bin mir nicht sicher, was ich falsch mache, aber ich versuche, ein MKMapViewObjekt zu berühren . Ich habe es durch Erstellen der folgenden Klasse in Unterklassen unterteilt:

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

@interface MapViewWithTouches : MKMapView {

}

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

@end

Und die Umsetzung:

#import "MapViewWithTouches.h"
@implementation MapViewWithTouches

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

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

}
@end

Aber es sieht so aus, als würde ich in dieser Klasse nichts auf der Konsole sehen:

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

Irgendeine Idee, was ich falsch mache?

Martin
quelle

Antworten:

147

Der beste Weg, dies zu erreichen, ist mit einem Gestenerkenner. Andere Möglichkeiten beinhalten eine Menge hackiger Programmierung, die Apples Code unvollständig dupliziert, insbesondere im Fall von Multitouch.

Folgendes mache ich: Implementiere einen Gestenerkenner, der nicht verhindert werden kann und der andere Gestenerkenner nicht verhindern kann. Fügen Sie es der Kartenansicht hinzu und verwenden Sie dann die BerührungenBegan, touchMoved usw. des gestureRecognizer nach Ihren Wünschen.

So erkennen Sie einen Tipp in einem MKMapView (ohne Tricks)

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
quelle
3
Wofür ist "LockedOnUserLocation"?
Jowie
Das ist eine fremde Variable, die für meine Anwendung spezifisch ist. Es verfolgt, ob das System die Karte automatisch auf den aktuellen Standort
zentrieren soll
Dies ist die perfekte Lösung. Ich benötige eine Klarstellung: In der Methode "- (void) berührtBegan: (NSSet *) berührt mit Ereignis: (UIEvent *) Ereignis", was ist der Zweck der Verwendung des Codes: if (BerührungenBeganCallback) berührtBeganCallback (Berührungen, Ereignis);
Satyam
1
Das funktioniert größtenteils großartig, aber ich habe ein Problem damit gefunden. Wenn der HTML-Code in Ihrer Webansicht ein HTML5- videoTag mit Steuerelementen enthält, verhindert die Gestenerkennung, dass der Benutzer die Steuerelemente verwenden kann. Ich habe nach einer Problemumgehung gesucht, aber noch keine gefunden.
Bryan Irace
Ich danke Ihnen für das Teilen. Warum es keine geeignete Delegierungsmethode zum Verfolgen von Benutzerinteraktionen mit einer Kartenansicht gibt, ist mir ein Rätsel, aber das funktioniert gut.
Justin Driscoll
29

Nach einem Tag voller Pizzen und Schreie fand ich endlich die Lösung! Sehr gepflegt!

Peter, ich habe deinen obigen Trick benutzt und ihn ein wenig optimiert, um endlich eine Lösung zu haben, die perfekt mit MKMapView funktioniert und auch mit UIWebView funktionieren sollte

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

Ich hoffe das wird einigen von euch helfen!

Prost

Martin
quelle
14
Nett. Kleiner Vorschlag: Sie sollten vermeiden, Ihre eigenen Klassen mit einem UI-Präfix zu benennen. Apple behält sich vor, NS oder UI als Klassenpräfix zu verwenden, da diese möglicherweise mit einer Apple-Klasse in Konflikt geraten (selbst wenn es sich um eine private Klasse handelt).
Daniel Dickison
Hey Daniel, du hast vollkommen recht, das habe ich auch gedacht! Um meine Antwort oben zu vervollständigen, möchte ich eine kleine Warnung hinzufügen: In meinem Beispiel wird davon ausgegangen, dass nur ein Objekt viewTouched vorhanden ist, das alle Ereignisse verbraucht. Das stimmt aber nicht. Sie könnten einige Anmerkungen oben auf Ihrer Karte haben und dann funktioniert mein Code nicht mehr. Um 100% zu arbeiten, müssen Sie sich für jeden Treffer die mit diesem bestimmten Ereignis verknüpfte Ansicht merken (und sie schließlich freigeben, wenn touchEnded oder touchCancelled ausgelöst wird, damit Sie die abgeschlossenen Ereignisse nicht verfolgen müssen ...).
Martin
1
Sehr nützlicher Code, danke Martin! Ich habe mich gefragt, ob Sie versucht haben, die Karte nach der Implementierung zu vergrößern. Für mich schien es zu funktionieren, als ich es mit im Grunde dem gleichen Code zum Laufen brachte, den Sie vor allem hatten, außer ein bisschen die Karte zu zoomen. Hat jemand irgendwelche Ideen?
Adam Alexander
Hey Adam, ich habe auch diese Einschränkung und ich verstehe nicht wirklich warum! Das ist wirklich nervig. Wenn Sie eine Lösung finden, lassen Sie es mich wissen! Thx
Martin
Ok, ich habe dieses gewählt, weil es anfangs mein Problem zu lösen schien. JEDOCH...! Ich kann nicht scheinen, Multi-Touch zum Laufen zu bringen. Das heißt, obwohl ich BerührungenBegan und BerührungenMoviert direkt an viewTouched übergebe (ich fange Berührungen ab), kann ich die Karte nicht mit Pinch-Gesten zoomen. (Fortsetzung ...)
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
quelle
3
Ich bin mir nicht sicher, warum dies nicht die beste Antwort ist. Scheint perfekt zu funktionieren und ist viel einfacher.
Elsurudo
12

Für ein MKMapView ist die eigentliche Arbeitslösung die Gestenerkennung!

Ich wollte die Aktualisierung der Kartenmitte an meinem Standort beenden, wenn ich die Karte ziehe oder zum Zoomen kneife.

Erstellen Sie also Ihren Gestenerkenner und fügen Sie ihn der mapView hinzu:

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

In der UIGestureRecognizer-Klassenreferenz finden Sie alle verfügbaren Gestenerkenner.

Da wir den Delegaten für sich selbst definiert haben, müssen wir das Protokoll UIGestureRecognizerDelegate implementieren:

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

Und überschreiben Sie die Methode gestureRecognizer: gestureRecognizer shouldRecognizeSimultaneousWithGestureRecognizer: um das gleichzeitige Erkennen mehrerer Gesten zu ermöglichen, wenn ich richtig verstanden habe:

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

Schreiben Sie nun die Methoden, die von unseren Gestenerkennern aufgerufen werden:

// 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
quelle
Diese Lösung ist perfekt! Einige Quickies hier: Wenn Sie abfangen möchten, wann der Benutzer keine Aktion mehr ausführt, sollte dies ausreichen - (void) handleLongPressAndPinchGesture: (UIGestureRecognizer *) sender {if (sender.state == UIGestureRecognizerStateEnded) {NSLog (@ "handleLongPressAndPinchGesture") ;; }}
Alejandro Luengo
Vergessen Sie auch nicht, den Delegaten <UIGestureRecognizerDelegate>
Alejandro Luengo am
6

Nur für den Fall, dass jemand versucht, dasselbe wie ich zu tun: Ich wollte an der Stelle, an der der Benutzer tippt, eine Anmerkung erstellen. Dafür habe ich die UITapGestureRecognizerLösung verwendet:

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

Wurde didTapOnMap:jedoch auch aufgerufen, als ich auf die Anmerkung tippte und eine neue erstellt wurde. Die Lösung besteht darin, Folgendes zu implementieren UIGestureRecognizerDelegate:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if ([touch.view isKindOfClass:[MKAnnotationView class]])
    {
        return NO;
    }
    return YES;
}
jimpic
quelle
Dies ist eine großartige Lösung! Es funktioniert jedoch nicht, wenn Sie eine benutzerdefinierte Ansicht als verwenden MKAnnotation. In diesem Fall kann die Unteransicht einer anderen Anmerkung die Gestenerkennung auslösen. Ich musste rekursiv die Übersicht der touch.view überprüfen, um eine mögliche MKAnnotationView
KIDdAe
3

Wahrscheinlich müssen Sie eine transparente Ansicht überlagern, um die Berührungen zu erfassen, wie dies bei UIWebView-basierten Steuerelementen so häufig der Fall ist. In der Kartenansicht werden bereits einige spezielle Aufgaben mit einem Tastendruck ausgeführt, damit die Karte verschoben, zentriert, gezoomt usw. werden kann, damit die Nachrichten nicht in Ihre App gelangen.

Zwei weitere (UNTESTED) Optionen, die mir einfallen:

1) Geben Sie den Ersthelfer über IB zurück und setzen Sie ihn auf "Dateibesitzer", damit der Dateibesitzer auf die Berührungen reagieren kann. Ich bin mir nicht sicher, ob dies funktionieren wird, da MKMapView NSObject erweitert, nicht UIView und ein Ergebnis, bei dem die Berührungsereignisse möglicherweise immer noch nicht an Sie weitergegeben werden.

2) Wenn Sie einfangen möchten, wenn sich der Map-Status ändert (z. B. bei einem Zoom), implementieren Sie einfach das MKMapViewDelegate-Protokoll, um auf bestimmte Ereignisse zu warten. Meine Vermutung ist, dass dies Ihre beste Möglichkeit ist, Interaktionen leicht einzufangen (ohne die transparente Ansicht über die Karte zu implementieren). Vergessen Sie nicht, den View Controller, in dem sich das MKMapView befindet, als Delegat der Karte festzulegen ( map.delegate = self).

Viel Glück.

MystikSpiral
quelle
MKMapView ist definitiv eine Unterklasse von UIView.
Daniel Dickison
2

Ich habe nicht experimentiert, aber es besteht eine gute Chance, dass MapKit auf einem Klassencluster basiert, und daher ist es schwierig und ineffektiv, es in Unterklassen zu unterteilen.

Ich würde vorschlagen, die MapKit-Ansicht zu einer Unteransicht einer benutzerdefinierten Ansicht zu machen, damit Sie Berührungsereignisse abfangen können, bevor sie diese erreichen.

Grahamparks
quelle
Hallo Graham! Danke für Ihre Hilfe! Wie kann ich Ereignisse an MKMapView weiterleiten, wenn ich eine von Ihnen vorgeschlagene super benutzerdefinierte Ansicht erstelle? Irgendeine Idee?
Martin
2

Nachdem ich einen halben Tag damit herumgespielt hatte, fand ich Folgendes:

  1. Wie alle anderen fanden, funktioniert das Kneifen nicht. Ich habe sowohl MKMapView als auch die oben beschriebene Methode ausprobiert (abgefangen). Und das Ergebnis ist das gleiche.
  2. In den Stanford iPhone-Videos sagt ein Mann von Apple, dass viele der UIKit-Dinge eine Menge Fehler verursachen, wenn Sie die Berührungsanforderungen "übertragen" (auch bekannt als die beiden oben beschriebenen Methoden), und Sie werden sie wahrscheinlich nicht zum Laufen bringen.

  3. DIE LÖSUNG : wird hier beschrieben: Abfangen / Entführen von iPhone Touch-Ereignissen für MKMapView . Grundsätzlich "fangen" Sie das Ereignis, bevor ein Antwortender es erhält, und interpretieren es dort.

thuang513
quelle
2

In 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
quelle
0

Machen Sie die MKMapView zu einer Unteransicht einer benutzerdefinierten Ansicht und implementieren Sie sie

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

in der benutzerdefinierten Ansicht, um self anstelle der Unteransicht zurückzugeben.

Peter N Lewis
quelle
Hallo Peter, Danke für deine Antwort! Aber ich denke, dass MKMapView auf diese Weise möglicherweise keine Touche-Ereignisse abrufen kann, nicht wahr? Ich suche nach einer Möglichkeit, ein Ereignis einfach abzufangen und dann an MKMapView weiterzuleiten.
Martin
0

Danke für die Pizza und die Schreie - du hast mir viel Zeit gespart.

multipletouchenabled funktioniert sporadisch.

viewTouch.multipleTouchEnabled = TRUE;

Am Ende habe ich die Ansichten ausgeschaltet, als ich die Berührung erfassen musste (anderer Zeitpunkt als Pinchzooms):

    [mapView removeFromSuperview];
    [viewTouch addSubview:mapView];
    [self.view insertSubview:viewTouch atIndex:0];
BankStrong
quelle
funktioniert aber nicht mit Live-Zoom. Es scheint auch immer herauszuzoomen.
Rog
0

Ich stelle fest, dass Sie die Anzahl und den Ort der Berührungen verfolgen und die Position der einzelnen Berührungen in einer Ansicht abrufen können:

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

Hat jemand anderes versucht, diese Werte zu verwenden, um die Zoomstufe der Karte zu aktualisieren? Es geht darum, die Startpositionen und dann die Zielpositionen aufzuzeichnen, die relative Differenz zu berechnen und die Karte zu aktualisieren.

Ich spiele mit dem von Martin bereitgestellten Basiscode und das sieht so aus, als würde es funktionieren ...

Dan Donaldson
quelle
0

Folgendes habe ich zusammengestellt, um das Zoomen im Simulator zu ermöglichen (ich habe es noch nicht auf einem echten iPhone versucht), aber ich denke, das wäre in Ordnung:

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

Die Hauptidee ist, dass Sie die Werte verfolgen, wenn der Benutzer zwei Finger verwendet. Ich zeichne die Start- und Endpunkte in den Startpunkten A und B auf. Dann zeichne ich die aktuellen Verfolgungspunkte auf. Wenn ich fertig bin, kann ich bei touchEnded eine Routine aufrufen, um die relativen Längen der Linie zwischen den Punkten zu berechnen, mit denen ich beginne und die Linie zwischen dem Punkt, an dem ich mit der einfachen Berechnung der Hypotenuse ende. Das Verhältnis zwischen ihnen ist der Zoombetrag: Ich multipliziere die Bereichsspanne mit diesem Betrag.

Hoffe, es ist nützlich für jemanden.

Dan Donaldson
quelle
0

Ich habe die Idee einer transparenten "Overlay" -Ansicht aus MystikSpirals Antwort übernommen und sie funktionierte perfekt für das, was ich erreichen wollte. schnelle und saubere Lösung.

Kurz gesagt, ich hatte eine benutzerdefinierte UITableViewCell (in IB entworfen) mit einem MKMapView auf der linken Seite und einigen UILabels auf der rechten Seite. Ich wollte die benutzerdefinierte Zelle so gestalten, dass Sie sie überall berühren können, und dies würde einen neuen Ansichts-Controller auslösen. Durch Berühren der Karte wurden jedoch keine Berührungen an die UITableViewCell übergeben, bis ich einfach eine UIView mit der gleichen Größe wie die Kartenansicht direkt darüber (in IB) hinzugefügt und den Hintergrund im Code als "klare Farbe" festgelegt habe (in IB). glaube nicht, dass du clearColor in IB setzen kannst ??):

dummyView.backgroundColor = [UIColor clearColor];

Dachte, es könnte jemand anderem helfen; sicherlich, wenn Sie dasselbe Verhalten für eine Tabellenansichtszelle erzielen möchten.

petert
quelle
"Das Berühren der Karte hat jedoch keine Berührungen an die UITableViewCell übergeben, bis ich einfach eine UIView mit der gleichen Größe wie die Kartenansicht direkt darüber hinzugefügt habe." Dies ist nicht wahr. Die Karte verarbeitet Berührungen, da sie über eigene Benutzerinteraktionen wie Scrollen usw. verfügt. Wenn Sie das In der Zelle erkennen möchten, anstatt mit der Karte zu interagieren, setzen Sie einfach map.isUserInteractionEnabled = false. Sie können dann einfach didSelectRowAtIndexPath in der Tabelle verwenden Delegat anzeigen.
BROK3N S0UL