Як перехопити події дотиків на об’єктах MKMapView або UIWebView?


96

Я не впевнений, що роблю неправильно, але намагаюся зачепити MKMapViewпредмет. Я підкласифікував його, створивши наступний клас:

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

@interface MapViewWithTouches : MKMapView {

}

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

@end

І реалізація:

#import "MapViewWithTouches.h"
@implementation MapViewWithTouches

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

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

}
@end

Але, схоже, коли я використовую цей клас, я нічого не бачу на консолі:

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

Будь-яка ідея, що я роблю неправильно?

Відповіді:


147

Найкращий спосіб, який я знайшов для досягнення цього - це за допомогою розпізнавача жестів. Інші способи, як виявляється, включають багато хакерських програм, які недосконало дублюють код Apple, особливо у випадку з мультитачем.

Ось що я роблю: Впроваджую розпізнавач жестів, який неможливо запобігти і який не може запобігти іншим розпізнавачам жестів. Додайте його до подання на карті, а потім використовуйте жест «Розпізнавач» touchBegan, touchesMoved тощо тощо.

Як виявити будь-який кран всередині MKMapView (без фокусів)

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

WildcardGestureRecognizer.h

//
//  WildcardGestureRecognizer.h
//  Copyright 2010 Floatopian LLC. All rights reserved.
//

#import <Foundation/Foundation.h>

typedef void (^TouchesEventBlock)(NSSet * touches, UIEvent * event);

@interface WildcardGestureRecognizer : UIGestureRecognizer {
    TouchesEventBlock touchesBeganCallback;
}
@property(copy) TouchesEventBlock touchesBeganCallback;


@end

WildcardGestureRecognizer.m

//
//  WildcardGestureRecognizer.m
//  Created by Raymond Daly on 10/31/10.
//  Copyright 2010 Floatopian LLC. All rights reserved.
//

#import "WildcardGestureRecognizer.h"


@implementation WildcardGestureRecognizer
@synthesize touchesBeganCallback;

-(id) init{
    if (self = [super init])
    {
        self.cancelsTouchesInView = NO;
    }
    return self;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (touchesBeganCallback)
        touchesBeganCallback(touches, event);
}

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

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

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

- (void)reset
{
}

- (void)ignoreTouch:(UITouch *)touch forEvent:(UIEvent *)event
{
}

- (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer
{
    return NO;
}

- (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer
{
    return NO;
}

@end

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"?
jowie

це стороння змінна, специфічна для мого додатка. він відстежує, чи повинна система автоматично
централізувати

Це ідеальне рішення. Мені потрібно одне пояснення: У методі "- (void) touchesBegan: (NSSet *) touches withEvent: (UIEvent *) event", яка мета використання коду: if (touchesBeganCallback) touchesBeganCallback (touch, event);
Satyam

1
Це працює чудово здебільшого, але я знайшов одну проблему з цим. Якщо HTML у вашому веб-поданні містить videoтег HTML5 з елементами керування, розпізнавач жестів не дозволить користувачеві мати можливість використовувати елементи керування. Я шукав вирішення цього питання, але ще не знайшов його.
Bryan Irace

Дякую, що поділились. Чому не існує підходящого методу делегації для відстеження взаємодій користувачів з поданням карти, це не можливо, але це добре працює.
Джастін Дрісколл

29

Після дня піци, крику я нарешті знайшов рішення! Дуже акуратно!

Пітере, я скористався твоїм трюком вище і трохи підправив його, щоб нарешті отримати рішення, яке чудово працює з MKMapView і має працювати також з 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

Я сподіваюся, що це допоможе комусь із вас!

Ура


14
Приємно. Невелика порада: слід уникати іменування власних класів префіксом інтерфейсу. Apple резервує / не рекомендує використовувати NS або UI як префікс класу, оскільки вони можуть закінчитися зіткненням із класом Apple (навіть якщо це приватний клас).
Даніель Дікісон

Гей, Даніеле, ти абсолютно прав, я теж думав, що! Щоб завершити мою відповідь вище, дозвольте мені додати невелике попередження: Мій приклад передбачає, що існує лише один об’єкт viewTouched, який споживає всі події. Але це неправда. Ви можете мати кілька анотацій поверх вашої карти, і тоді мій код більше не працює. Щоб працювати на 100%, вам потрібно запам’ятати для кожного хіту Тест подання, пов’язаного з цією конкретною подією (і врешті-решт звільнити його, коли спрацьовує touchesEnded або touchesCancelled, тому вам не потрібно відстежувати закінчені події ...).
Мартін

1
Дуже корисний код, дякую Мартіне! Мені було цікаво, чи ви спробували масштабувати масштабну карту після цього? Для мене, коли я працював, використовуючи в основному той же код, який у вас вище, здавалося, працює, за винятком дрібного масштабування карти. У когось є якісь ідеї?
Адам Олександр

Гей, Адам, у мене теж є таке обмеження, і я не розумію чому! Це насправді дратує. Якщо ви знайдете рішення, дайте мені знати! Thx
Мартін

Гаразд, я проголосував за це, оскільки спочатку, здавалося, вирішувалася моя проблема. ЯКЩО ...! Мені здається, я не можу змусити працювати дотиком. Тобто, хоча я безпосередньо передаю дотикиПочаток і дотикиПеремещено viewTouched (я перехоплюю дотики до кінця), я не можу масштабувати карту щипковими жестами. (Продовження ...)
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
Я не впевнений, чому це не головна відповідь. Здається, працює ідеально і набагато простіше.
elsurudo

12

Для MKMapView справжнім робочим рішенням є розпізнавання жестів!

Мені хотілося припинити оновлення центру карти на моєму місцезнаходженні, коли я перетягую карту або стискаю для збільшення.

Отже, створіть і додайте розпізнавач жестів до 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];
}

Перегляньте довідник класу UIGestureRecognizer, щоб побачити всі доступні розпізнавачі жестів.

Оскільки ми визначили делегата до self, ми повинні реалізувати протокол 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;
...

І перевизначити метод methode gestureRecognizer: gestureRecognizer shouldRecognizeSim istovremenolyWithGestureRecognizer: для того, щоб дозволити розпізнавати кілька жестів одночасно, якщо я правильно зрозумів:

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

Тепер напишіть методи, які будуть викликані нашими розпізнавальниками жестів:

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

Це рішення ідеально! Деякі швидкі запити тут: Якщо ви хочете перехопити, коли користувач закінчить робити будь-які дії, використовуючи це, слід передбачити - (void) handleLongPressAndPinchGesture: (UIGestureRecognizer *) відправник {if (sender.state == UIGestureRecognizerStateEnded) {NSLog (@ "handleLongchestPestAndPestAndPureAndPureAndPureAndPureAndPongAndPureAndPongPestAndPongAndPestAndPestAndPongAndPestAndPongPestAndPandAndPongAndPandAndPongAndPandAndPongPestAndPandAndPestAndPandAndPestAndPandAndPongAndPestAnd) ; }}
Алехандро Луенго

Також не забудьте додати делегата <UIGestureRecognizerDelegate>
Алехандро Луенго

6

Про всяк випадок, коли хтось намагається зробити те саме, що і я: я хотів створити анотацію в точці, коли користувач натискає. Для цього я використав UITapGestureRecognizerрішення:

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

Однак, didTapOnMap:зателефонували, коли я натиснув на анотацію, і буде створено нове. Рішення полягає у здійсненні UIGestureRecognizerDelegate:

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

Це чудове рішення! Але це не спрацьовує, якщо ви використовуєте спеціальний вигляд як MKAnnotation. У цьому випадку у вас може бути інший підвид підказки, який викликає розпізнавальник жестів. Мені довелося рекурсивно перевіряти супергляд сенсорного перегляду, щоб знайти потенційний MKAnnotationView
KIDdAe

3

Вам, мабуть, знадобиться накласти прозорий вигляд, щоб зафіксувати дотики так, як це часто робиться з елементами управління на основі UIWebView. Перегляд карти вже робить купу особливих речей з одним дотиком, щоб дозволити мапі переміщати, центрувати, масштабувати тощо ... щоб повідомлення не потрапляли у ваш додаток.

Ще два (НЕТЕСТОВАНІ) варіанти, які я можу придумати:

1) Відправте першого респондента через IB та встановіть його на "Власник файлу", щоб власник файлу міг відповісти на дотики. Я сумніваюся, що це спрацює, оскільки MKMapView розширює NSObject, а не UIView, і в результаті події дотику все ще можуть не поширюватися до вас.

2) Якщо ви хочете перехопити, коли стан карти змінюється (наприклад, при масштабуванні), просто впровадьте протокол MKMapViewDelegate для прослуховування певних подій. Моя думка - це ваш найкращий випадок, коли легко взаємодієте у взаємодії (за винятком впровадження прозорого "Погляду над картою") Не забудьте встановити контролер перегляду, в якому розміщений MKMapView, як делегат карти ( map.delegate = self).

Щасти.


MKMapView безумовно підкласи UIView.
Даніель Дікісон

2

Я не експериментував, але є велика ймовірність, що MapKit базується на кластері класів, і тому його класифікація складна та неефективна.

Я б запропонував зробити MapKit переглядом підвидом власного перегляду, який повинен дозволити вам перехоплювати події дотику, перш ніж вони досягнуть його.


Привіт, Грем! Дякую за твою допомогу! Якщо я сформував супервидовий перегляд, як ви пропонуєте, як я можу потім переслати події в MKMapView? Будь-яка ідея?
Мартін

2

Тож через півдня возитися з цим я виявив таке:

  1. Як виявили всі інші, щипання не працює. Я спробував як підклас MKMapView, так і метод, описаний вище (перехоплюючи його). І результат той самий.
  2. У відеофільмах із Стенфорда для iPhone хлопець із Apple каже, що багато речей з UIKit спричиняють чимало помилок, якщо ви "переносите" запити на дотик (вони ж два описані вище методи), і ви, мабуть, не змусите його працювати.

  3. РІШЕННЯ : описано тут: Перехоплення / викрадення iPhone Touch подій для MKMapView . В основному ви "ловите" подію до того, як її отримає будь-який респондент, і інтерпретуєте її там.


2

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

    }

}

0

Зробіть MKMapView підвидом власного подання та реалізації

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

у власному поданні повернути self замість subview.


Привіт Петре, дякую за відповідь! Але я думаю, що, зробивши це, MKMapView не зможе отримати жодних торкаючих подій, чи не так? Я шукаю спосіб просто вловити подію, а потім переслати її до MKMapView.
Мартін

0

Дякую за піцу та крики - ти врятував мені багато часу.

multipletouchenabled працюватиме епізодично.

viewTouch.multipleTouchEnabled = TRUE;

Врешті-решт, я вимкнув види, коли мені потрібно було зафіксувати дотик (інший момент часу, ніж потрібні пінч-зуми):

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

але не працює з масштабуванням у реальному часі. Здається, це завжди зменшує масштаб.
Рог,

0

Я помічаю, що ви можете відстежувати кількість та розташування дотиків та отримувати розташування кожного з них:

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

Хтось ще намагався використовувати ці значення для оновлення рівня масштабування карти? Йшлося б про запис початкових позицій, а потім фінішних місць, обчислення відносної різниці та оновлення карти.

Я граюся з основним кодом, наданим Мартіном, і, схоже, це буде працювати ...


0

Ось те, що я зібрав, що дозволяє в масштабній мірі масштабувати симулятор (ще не пробував справжній iPhone), але я думаю, що це буде добре:

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

Основна ідея полягає в тому, що якщо користувач використовує два пальці, ви відстежуєте значення. Я записую початкову і кінцеву точки в стартових точках А і В. Потім записую поточні точки відстеження, і коли я закінчу, на дотики Закінчено, я можу викликати процедуру обчислення відносної довжини лінії між точками, з яких починаю , і лінія між точкою, яку я закінчую, використовуючи просту гіпотенузу calc. Співвідношення між ними - це масштаб: я помножую діапазон області на цю величину.

Сподіваюся, це комусь корисно.


0

Я взяв ідею "накладеного" прозорого погляду з відповіді MystikSpiral, і він ідеально працював для того, чого я намагався досягти; швидке і чисте рішення.

Коротше кажучи, у мене була спеціальна UITableViewCell (розроблена в IB) з MKMapView зліва та деякими UIL-мітками праворуч. Я хотів зробити власну комірку, щоб ви могли торкнутися її де завгодно, і це призведе до нового контролера перегляду. Однак торкання карти не передавало штрихів "вгору" UITableViewCell, поки я просто не додав UIView такого ж розміру, як вигляд карти, прямо над ним (у IB) і зробив його фоном "чітким кольором" у коді ( не думайте, що ви можете встановити clearColor у IB ??):

dummyView.backgroundColor = [UIColor clearColor];

Думав, що це може допомогти комусь іншому; звичайно, якщо ви хочете досягти такої ж поведінки для комірки подання таблиці.


"Однак дотик до карти не передавав" дотику "до UITableViewCell, поки я просто не додав UIView того самого розміру, що і вид на карті, прямо над нею" Це неправда. Карта обробляє штрихи, оскільки вона має власні взаємодії з користувачами, такі як прокрутка і т. Д. Якщо ви хочете виявити хоч у клітинці, а не взаємодіяти з картою, просто встановіть map.isUserInteractionEnabled = false Ви можете просто використовувати didSelectRowAtIndexPath у таблиці переглянути делегат.
BROK3N S0UL
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.