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의 코드를 불완전하게 복제하는 많은 해킹 프로그래밍을 포함하는 것으로 밝혀졌습니다.

내가하는 일은 다음과 같습니다. 방지 할 수없고 다른 제스처 인식기를 방지 할 수없는 제스처 인식기를 구현합니다. 지도보기에 추가 한 다음 gestureRecognizer의 touchesBegan, 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 2011 년

그것은 내 응용 프로그램과 관련된 외부 변수입니다. 시스템이 자동으로 현재 위치의지도 중앙에 위치
해야하는지

이것은 완벽한 솔루션입니다. 한 가지 설명이 필요합니다. "-(void) touchesBegan : (NSSet *) touches withEvent : (UIEvent *) event"메서드에서 코드를 사용하는 목적은 무엇입니까? if (touchesBeganCallback) touchesBeganCallback (touches, event);
Satyam

1
이것은 대부분 잘 작동하지만 한 가지 문제를 발견했습니다. 웹보기의 HTML에 video컨트롤 이있는 HTML5 태그가 포함 된 경우 제스처 인식기는 사용자가 컨트롤을 사용할 수 없도록합니다. 나는 이것에 대한 해결 방법을 찾고 있었지만 아직 찾지 못했습니다.
Bryan Irace 2011-04-01

공유 해주셔서 감사합니다. 지도보기와 사용자 상호 작용을 추적하는 데 적합한 델리게이트 방법이없는 이유는 저를 넘어서지 만 잘 작동합니다.
Justin Driscoll 2012 년

29

피자와 비명을 지르며 하루를 보낸 후 마침내 해결책을 찾았습니다! 매우 깔끔합니다!

Peter, 위의 트릭을 사용하고 마침내 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
좋은. 작은 제안 : UI 접두사로 클래스 이름을 지정하지 않아야합니다. Apple은 NS 또는 UI를 클래스 접두사로 사용하는 것을 유보 / 금지합니다. 이는 Apple 클래스와 충돌 할 수 있기 때문입니다 (개인 클래스라도).
Daniel Dickison

헤이 다니엘, 당신 말이 맞아 나도 그렇게 생각 했어! 위의 대답을 완료하기 위해 약간의 경고를 추가하겠습니다. My Example에서는 모든 이벤트를 소비하는 하나의 개체 viewTouched 만 있다고 가정합니다. 그러나 그것은 사실이 아닙니다. 지도 위에 주석이있을 수 있으며 내 코드가 더 이상 작동하지 않습니다. 100 % 작업하려면 각 hitTest에 대해 해당 특정 이벤트와 관련된 뷰를 기억해야합니다 (그리고 결국 touchesEnded 또는 touchesCancelled가 트리거 될 때이를 해제하므로 완료된 이벤트를 추적 할 필요가 없습니다 ...).
Martin

1
매우 유용한 코드, 감사합니다 Martin! 이것을 구현 한 후지도를 핀치 확대 해 보았는지 궁금합니다. 나를 위해 기본적으로 동일한 코드를 사용하여 작동했을 때지도를 핀치 줌하는 것을 제외하고는 모든 것이 작동하는 것처럼 보였습니다. 누구나 아이디어가 있습니까?
Adam Alexander

아담, 저도이 한계가 있는데 왜 그런지 모르겠습니다! 정말 짜증납니다. 해결책을 찾으면 알려주세요! Thx
Martin

좋아, 처음에는 내 문제를 해결하는 것처럼 보였기 때문에이 항목에 투표했습니다. 하나...! 멀티 터치가 작동하지 않는 것 같습니다. 즉, touchesBegan 및 touchesMoved를 viewTouched로 직접 전달하더라도 (touchesEnded에서 인터 셉팅 수행) 핀치 제스처로지도를 확대 / 축소 할 수 없습니다. (계속 ...)
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;
...

그리고 여러 제스처를 동시에 인식하도록하려면 gestureRecognizer : gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer : 메서드를 재정의합니다.

// 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 *) sender {if (sender.state == UIGestureRecognizerStateEnded) {NSLog (@ "handleLongPressAndPinchGesture Ended") ; }}
Alejandro Luengo

또한 <UIGestureRecognizerDelegate> 대리자를 추가하는 것을 잊지 마세요
알레한드로 Luengo

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를 찾기 위해 touch.view의 수퍼 뷰를 재귀 적으로 확인해야했습니다.
KIDdAe

3

UIWebView 기반 컨트롤로 자주 수행되는 것처럼 터치를 포착하려면 투명 뷰를 오버레이해야 할 것입니다. 지도보기는 메시지가 앱에 표시되지 않는지도를 이동, 중앙, 확대 / 축소하는 등의 작업을 수행하기 위해 이미 터치로 여러 가지 특별한 작업을 수행합니다.

생각할 수있는 다른 두 가지 (UNTESTED) 옵션 :

1) IB를 통해 첫 번째 응답자를 사임하고 파일 소유자가 터치에 응답 할 수 있도록 "파일 소유자"로 설정합니다. MKMapView가 UIView가 아닌 ​​NSObject를 확장하기 때문에 이것이 작동 할 것이라고 의심 스럽습니다. 그 결과 터치 이벤트가 여전히 당신에게 전파되지 않을 수 있습니다.

2) 맵 상태가 변경 될 때 (예 : 확대 / 축소에서) 트랩하려면 MKMapViewDelegate 프로토콜을 구현하여 특정 이벤트를 수신하십시오. 내 직감은 이것이 상호 작용을 쉽게 포착하는 최선의 방법입니다 (지도 위에 투명한 뷰를 구현하는 것보다 부족함). MKMapView를 포함하는 View Controller를 맵의 델리게이트로 설정하는 것을 잊지 마십시오 (map.delegate = self ) .

행운을 빕니다.


MKMapView는 확실히 UIView를 하위 클래스로 만듭니다.
Daniel Dickison

2

나는 실험하지 않았지만 MapKit이 클래스 클러스터를 기반으로 할 가능성이 있으므로 서브 클래 싱이 어렵고 비효율적입니다.

터치 이벤트가 도달하기 전에 가로 챌 수 있도록 MapKit보기를 사용자 정의보기의 하위보기로 만드는 것이 좋습니다.


안녕하세요 그레이엄! 도와 주셔서 감사합니다! 당신이 제안한 것처럼 슈퍼 커스텀 뷰를 만들면 어떻게 이벤트를 MKMapView로 전달할 수 있습니까? 어떤 생각?
Martin

2

그래서 반나절 동안 이것을 엉망으로 만든 후 다음을 발견했습니다.

  1. 다른 사람들이 발견했듯이 꼬집음은 작동하지 않습니다. MKMapView를 서브 클래 싱하고 위에서 설명한 방법을 모두 시도했습니다 (차단). 결과는 동일합니다.
  2. Stanford iPhone 비디오에서 Apple의 한 사람은 터치 요청 (위에 설명 된 두 가지 방법이라고도 함)을 "전송"하면 UIKit의 많은 것들이 많은 오류를 일으키고 아마 작동하지 않을 것이라고 말합니다.

  3. 해결책 : 여기에 설명되어 있습니다 : MKMapView에 대한 iPhone 터치 이벤트 가로 채기 / 하이재킹 . 기본적으로 응답자가 이벤트를 받기 전에 이벤트를 "잡아"거기서 해석합니다.


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를 반환합니다.


안녕하세요 Peter, 답변 해 주셔서 감사합니다! 그러나 그렇게하면 MKMapView가 터치 이벤트를 얻지 못할 수도 있다고 생각합니다. 이벤트를 포착 한 다음 MKMapView로 전달하는 방법을 찾고 있습니다.
Martin

0

피자와 비명을 지르셔서 감사합니다. 시간을 많이 절약 해 주셨습니다.

multipletouchenabled는 산발적으로 작동합니다.

viewTouch.multipleTouchEnabled = TRUE;

결국 터치를 캡처해야 할 때 뷰를 전환했습니다 (핀치 줌이 필요한 시점과 다른 시점).

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

그러나 라이브 줌에서는 작동하지 않습니다. 또한 항상 축소되는 것 같습니다.
Rog

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

다른 사람이이 값을 사용하여지도의 확대 / 축소 수준을 업데이트하려고 한 적이 있습니까? 시작 위치를 기록한 다음 종료 위치를 기록하고 상대적 차이를 계산하고 맵을 업데이트하는 문제입니다.

Martin이 제공 한 기본 코드를 가지고 놀고 있는데, 이것이 작동 할 것 같습니다.


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

주요 아이디어는 사용자가 두 손가락을 사용하는 경우 값을 추적한다는 것입니다. 시작점 A와 B에 시작점과 끝점을 기록합니다. 그런 다음 현재 추적 점을 기록하고 완료되면 touchesEnded에서 루틴을 호출하여 시작점 사이의 선의 상대적 길이를 계산할 수 있습니다. , 그리고 간단한 빗변 계산을 사용하여 끝나는 점 사이의 선. 그들 사이의 비율은 확대 / 축소 정도입니다. 영역 범위에 그 정도를 곱합니다.

누군가에게 유용하기를 바랍니다.


0

MystikSpiral의 답변에서 "오버레이"투명 뷰라는 아이디어를 가져 왔고 제가 달성하려는 작업에 완벽하게 작동했습니다. 빠르고 깨끗한 솔루션.

요컨대, 왼쪽에 MKMapView가 있고 오른쪽에 일부 UILabels가있는 사용자 지정 UITableViewCell (IB에서 설계됨)이 있습니다. 사용자 지정 셀을 만들고 싶었으므로 어디에서나 터치하면 새로운 뷰 컨트롤러가 푸시됩니다. 그러나지도를 터치해도 바로 위에지도보기와 동일한 크기의 UIView (IB)를 추가하고 코드에서 배경을 '명확한 색상'으로 만들기 전까지는 UITableViewCell에 터치가 '위로'전달되지 않았습니다. IB에서 clearColor를 설정할 수 있다고 생각하지 않습니까 ??) :

dummyView.backgroundColor = [UIColor clearColor];

다른 사람에게 도움이 될 것이라고 생각했습니다. 확실히 테이블 뷰 셀에 대해 동일한 동작을 달성하려는 경우.


"하지만지도를 터치해도 UITableViewCell에 터치가 '위로'전달되지 않았습니다. 바로 위에지도보기와 동일한 크기의 UIView를 추가하기 전까지는"이것은 사실이 아닙니다. 지도는 스크롤과 같은 자체 사용자 상호 작용이 있기 때문에 터치를 처리하고 있습니다.지도와 상호 작용하는 대신 셀에서 그래도를 감지하려면 간단히 map.isUserInteractionEnabled = false를 설정하면됩니다. 그런 다음 테이블에서 didSelectRowAtIndexPath를 사용할 수 있습니다. 보기 대리인.
BROK3N S0UL
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.