จะสกัดกั้นการสัมผัสเหตุการณ์บนวัตถุ 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

แต่ดูเหมือนว่าเมื่อฉันใช้คลาสนี้ฉันไม่เห็นอะไรเลยใน Console:

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

มีความคิดว่าฉันทำอะไรผิดหรือเปล่า?

คำตอบ:


147

วิธีที่ดีที่สุดที่ฉันพบในการบรรลุเป้าหมายนี้คือการใช้ Gesture Recognizer วิธีอื่น ๆ ที่เกี่ยวข้องกับการเขียนโปรแกรมแฮ็กจำนวนมากซึ่งทำให้รหัสของ Apple ซ้ำกันอย่างไม่สมบูรณ์โดยเฉพาะในกรณีของมัลติทัช

นี่คือสิ่งที่ฉันทำ: ติดตั้งระบบจดจำท่าทางที่ไม่สามารถป้องกันได้และไม่สามารถป้องกันตัวจดจำท่าทางอื่น ๆ ได้ เพิ่มลงในมุมมองแผนที่จากนั้นใช้ TouchBegan, touchMoved และอื่น ๆ เพื่อจินตนาการของคุณ

วิธีตรวจจับการแตะใด ๆ ภายใน 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
"lockOnUserLocation" เพื่ออะไร
jowie

นั่นเป็นตัวแปรภายนอกเฉพาะสำหรับแอปพลิเคชันของฉัน มันติดตามว่าระบบควรตั้งศูนย์กลางของแผนที่ไว้ที่ตำแหน่งปัจจุบันโดยอัตโนมัติหรือไม่
gonzojive

นี่คือทางออกที่สมบูรณ์แบบ ฉันต้องการคำชี้แจงอย่างใดอย่างหนึ่ง: ในวิธีการ "- (โมฆะ) touchBegan: (NSSet *) สัมผัส withEvent: (UIEvent *) เหตุการณ์" จุดประสงค์ของการใช้รหัสคืออะไร: ถ้า (touchBeganCallback) สัมผัส BeganCallback (สัมผัสเหตุการณ์);
Satyam

1
วิธีนี้ใช้งานได้ดีเป็นส่วนใหญ่ แต่ฉันพบปัญหาอย่างหนึ่ง หาก HTML ในมุมมองเว็บของคุณมีvideoแท็กHTML5 ที่มีการควบคุมเครื่องมือจดจำท่าทางจะป้องกันไม่ให้ผู้ใช้สามารถใช้การควบคุมได้ ฉันกำลังมองหาวิธีแก้ปัญหานี้ แต่ยังไม่พบ
Bryan Irace

ขอบคุณสำหรับการแชร์. เหตุใดจึงไม่มีวิธีการมอบสิทธิ์ที่เหมาะสมในการติดตามการโต้ตอบของผู้ใช้ด้วยมุมมองแผนที่จึงเป็นสิ่งที่เหนือกว่าฉัน แต่วิธีนี้ใช้ได้ดี
Justin Driscoll

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 ม

#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

เฮ้แดเนียลคุณพูดถูกจริงๆฉันก็คิดแบบนั้นด้วย! เพื่อให้คำตอบด้านบนสมบูรณ์ให้ฉันเพิ่มคำเตือนเล็กน้อย: ตัวอย่างของฉันสมมติว่ามีเพียงมุมมองวัตถุเพียงรายการเดียวที่ใช้งานเหตุการณ์ทั้งหมด แต่นั่นไม่เป็นความจริง คุณสามารถมีคำอธิบายประกอบบางอย่างที่ด้านบนของแผนที่จากนั้นรหัสของฉันจะใช้งานไม่ได้อีกต่อไป เพื่อให้ทำงานได้ 100% คุณต้องจำไว้สำหรับแต่ละ hitTest มุมมองที่เกี่ยวข้องกับเหตุการณ์นั้น ๆ (และในที่สุดก็จะปล่อยเมื่อ touchEnded หรือ touchCancelled ถูกทริกเกอร์ดังนั้นคุณจึงไม่จำเป็นต้องติดตามเหตุการณ์ที่เสร็จสิ้น ... )
Martin

1
รหัสที่มีประโยชน์มากขอบคุณ Martin! ฉันสงสัยว่าคุณลองย่อแผนที่หลังจากใช้สิ่งนี้หรือไม่? สำหรับฉันเมื่อฉันทำให้มันใช้งานได้โดยใช้รหัสเดียวกับที่คุณมีเหนือทุกอย่างดูเหมือนจะใช้งานได้ยกเว้นการซูมแผนที่ ใครมีไอเดียบ้าง
Adam Alexander

เฮ้อดัมฉันมีข้อ จำกัด นี้ด้วยและฉันก็ไม่เข้าใจว่าทำไม! ที่น่ารำคาญจริงๆ หากคุณพบวิธีแก้ไขแจ้งให้เราทราบ! Thx
Martin

ตกลงฉันโหวตอันนี้เพราะตอนแรกดูเหมือนจะแก้ปัญหาของฉันได้ อย่างไรก็ตาม ... ! ดูเหมือนว่าฉันจะไม่สามารถใช้งานมัลติทัชได้ นั่นคือแม้ว่าฉันจะผ่านการสัมผัสสัมผัส Began และ TouchMoved โดยตรงเพื่อ viewTouched (ฉันทำการสกัดกั้นเมื่อสัมผัส TouchEnded) ฉันไม่สามารถซูมแผนที่ด้วยท่าทางบีบนิ้วได้ (ต่อ ... )
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เพื่อดูเครื่องมือจดจำท่าทางที่มีอยู่ทั้งหมด

เนื่องจากเราได้กำหนดผู้รับมอบสิทธิ์เป็นตัวเองเราจึงต้องใช้ 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;
...

และลบล้างท่าทางของเมท ธ อร์ Recognizer: ท่าทางRecognizer shouldRecognizeSim พร้อมกันWithGestureRecognizer: เพื่อให้สามารถจดจำท่าทางสัมผัสหลายอย่างพร้อมกันได้ถ้าฉันเข้าใจถูก:

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

โซลูชั่นนี้สมบูรณ์แบบ! ตัวอย่างรวดเร็วที่นี่: หากคุณต้องการแทรกแซงเมื่อผู้ใช้สิ้นสุดการดำเนินการใด ๆ โดยใช้สิ่งนี้ควรจะเพียงพอ - (โมฆะ) handleLongPressAndPinchGesture: (UIGestureRecognizer *) ผู้ส่ง {if (sender.state == UIGestureRecognizerStateEnded) {NSLog (EndLongPressAndPinch) ; }}
Alejandro Luengo

อย่าลืมเพิ่มผู้รับมอบสิทธิ์ <UIGestureRecognizerDelegate>
Alejandro 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. ในกรณีนี้คุณอาจมีมุมมองย่อยของคำอธิบายประกอบอื่นที่เรียกใช้เครื่องมือจดจำท่าทาง ฉันต้องตรวจสอบ superview ของ touch.view ซ้ำ ๆ เพื่อค้นหา MKAnnotationView ที่เป็นไปได้
KIDdAe

3

คุณอาจจะต้องวางซ้อนมุมมองแบบโปร่งใสเพื่อจับการสัมผัสเหมือนกับที่ทำบ่อยๆด้วยการควบคุมที่ใช้ UIWebView มุมมองแผนที่ทำสิ่งพิเศษมากมายด้วยการสัมผัสเพื่อให้แผนที่สามารถเคลื่อนย้ายจัดกึ่งกลางซูม ฯลฯ ... โดยที่ข้อความจะไม่ปรากฏในแอปของคุณ

อีกสองตัวเลือก (ยังไม่ได้ทดสอบ) ที่ฉันคิดได้:

1) ลาออกจากการตอบกลับคนแรกผ่าน IB และตั้งค่าเป็น "เจ้าของไฟล์" เพื่อให้เจ้าของไฟล์ตอบสนองต่อการสัมผัส ฉันไม่แน่ใจว่าสิ่งนี้จะได้ผลเพราะ MKMapView ขยาย NSObject ไม่ใช่ UIView และผลลัพธ์ที่เหตุการณ์การสัมผัสยังคงไม่ได้รับการเผยแพร่ให้กับคุณ

2) หากคุณต้องการดักจับเมื่อสถานะแผนที่เปลี่ยนไป (เช่นในการซูม) เพียงแค่ใช้โปรโตคอล MKMapViewDelegate เพื่อฟังเหตุการณ์เฉพาะ ลางสังหรณ์ของฉันนี่คือช็อตที่ดีที่สุดของคุณในการดักจับการโต้ตอบบางอย่างได้อย่างง่ายดาย (ไม่ได้ใช้มุมมองโปร่งใสบนแผนที่) อย่าลืมตั้งค่า View Controller ที่อยู่อาศัย MKMapView เป็นตัวแทนของแผนที่ ( map.delegate = self)

โชคดี.


MKMapView คลาสย่อยแน่นอน UIView
Daniel Dickison

2

ฉันไม่ได้ทดลอง แต่มีโอกาสดีที่ MapKit จะขึ้นอยู่กับคลัสเตอร์คลาสดังนั้นการจัดคลาสย่อยจึงเป็นเรื่องยากและไม่ได้ผล

ฉันขอแนะนำให้ทำให้มุมมอง MapKit เป็นมุมมองย่อยของมุมมองที่กำหนดเองซึ่งจะช่วยให้คุณสามารถสกัดกั้นเหตุการณ์การสัมผัสได้ก่อนที่จะไปถึง


สวัสดีเกรแฮม! ขอขอบคุณสำหรับความช่วยเหลือของคุณ! หากฉันสร้างมุมมองแบบกำหนดเองขั้นสูงอย่างที่คุณแนะนำฉันจะส่งต่อเหตุการณ์ไปยัง MKMapView ได้อย่างไร ความคิดใด ๆ ?
Martin

2

หลังจากครึ่งวันของการยุ่งกับสิ่งนี้ฉันพบสิ่งต่อไปนี้:

  1. อย่างที่คนอื่น ๆ พบการบีบนิ้วไม่ได้ผล ฉันลองทั้งคลาสย่อย MKMapView และวิธีการที่อธิบายไว้ข้างต้น (สกัดกั้นมัน) และผลลัพธ์ก็เหมือนกัน
  2. ในวิดีโอ iPhone ของ Stanford ผู้ชายคนหนึ่งจาก Apple กล่าวว่าสิ่งต่างๆของ UIKit จะทำให้เกิดข้อผิดพลาดมากมายหากคุณ "โอน" คำขอการสัมผัส (หรือที่เรียกว่าสองวิธีที่อธิบายไว้ข้างต้น) และคุณอาจไม่สามารถใช้งานได้

  3. โซลูชั่นที่ : อธิบายไว้ที่นี่: การสกัด / หักหลัง iPhone สัมผัสกิจกรรมสำหรับ 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

ในมุมมองแบบกำหนดเองเพื่อส่งคืนตนเองแทนมุมมองย่อย


สวัสดีปีเตอร์ขอบคุณสำหรับคำตอบ! แต่ฉันคิดว่าการทำเช่นนั้น 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];
}

มีใครอีกบ้างที่ลองใช้ค่าเหล่านี้เพื่ออัปเดตระดับการซูมของแผนที่ มันจะเป็นเรื่องของการบันทึกตำแหน่งเริ่มต้นจากนั้นตำแหน่งสิ้นสุดการคำนวณความแตกต่างสัมพัทธ์และการอัปเดตแผนที่

ฉันกำลังเล่นกับรหัสพื้นฐานที่มาร์ตินให้มาและดูเหมือนว่ามันจะใช้งานได้ ...


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 จากนั้นฉันจะบันทึกจุดติดตามปัจจุบันและเมื่อฉันทำเสร็จแล้วเมื่อแตะที่สิ้นสุดฉันสามารถเรียกรูทีนเพื่อคำนวณความยาวสัมพัทธ์ของเส้นระหว่างจุดที่ฉันเริ่มต้นด้วย และเส้นระหว่างจุดที่ฉันลงท้ายด้วยการคำนวณด้านตรงข้ามมุมฉากอย่างง่าย อัตราส่วนระหว่างพวกเขาคือจำนวนการซูม: ฉันคูณขอบเขตพื้นที่ด้วยจำนวนนั้น

หวังว่าจะมีประโยชน์กับใครบางคน


0

ฉันใช้แนวคิดของมุมมองที่โปร่งใส "ซ้อนทับ" จากคำตอบของ MystikSpiral และมันก็ทำงานได้อย่างสมบูรณ์แบบสำหรับสิ่งที่ฉันพยายามจะบรรลุ โซลูชันที่รวดเร็วและสะอาด

ในระยะสั้นฉันมี UITableViewCell ที่กำหนดเอง (ออกแบบใน IB) พร้อม MKMapView ทางด้านซ้ายมือและป้ายกำกับ UIL บางส่วนทางด้านขวา ฉันต้องการสร้างเซลล์ที่กำหนดเองเพื่อให้คุณสามารถสัมผัสได้ทุกที่และสิ่งนี้จะผลักดันตัวควบคุมมุมมองใหม่ อย่างไรก็ตามการแตะแผนที่ไม่ได้ผ่านการแตะ "ขึ้น" ไปที่ UITableViewCell จนกว่าฉันจะเพิ่ม UIView ที่มีขนาดเท่ากับมุมมองแผนที่ที่ด้านบน (ใน IB) และทำให้พื้นหลังเป็น 'สีที่ชัดเจน' ในโค้ด ( ไม่คิดว่าคุณจะสามารถตั้งค่า clearColor ใน IB ได้ ??):

dummyView.backgroundColor = [UIColor clearColor];

คิดว่ามันอาจช่วยคนอื่นได้ แน่นอนว่าคุณต้องการให้เกิดพฤติกรรมเดียวกันสำหรับเซลล์มุมมองตาราง


"อย่างไรก็ตามการแตะแผนที่ไม่ได้ผ่านการแตะ" ขึ้น "ไปที่ UITableViewCell จนกว่าฉันจะเพิ่ม UIView ขนาดเดียวกับมุมมองแผนที่ที่ด้านบน" ไม่เป็นความจริง แผนที่กำลังประมวลผลการสัมผัสเนื่องจากมีการโต้ตอบกับผู้ใช้เช่นการเลื่อนเป็นต้นหากคุณต้องการตรวจจับแม้ว่าบนเซลล์แทนที่จะโต้ตอบกับแผนที่เพียงแค่ตั้งค่า map.isUserInteractionEnabled = false จากนั้นคุณสามารถใช้ didSelectRowAtIndexPath ในตารางได้ ดูผู้รับมอบสิทธิ์
BROK3N S0UL
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.