Làm cách nào để chặn các sự kiện chạm vào đối tượng MKMapView hoặc UIWebView?


96

Tôi không chắc mình đang làm gì sai nhưng tôi cố gắng bắt lấy một MKMapViewvật thể chạm vào . Tôi đã phân lớp nó bằng cách tạo lớp sau:

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

@interface MapViewWithTouches : MKMapView {

}

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

@end

Và việc thực hiện:

#import "MapViewWithTouches.h"
@implementation MapViewWithTouches

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

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

}
@end

Nhưng có vẻ như khi tôi sử dụng lớp này, tôi không thấy gì trên Bảng điều khiển:

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

Bất kỳ ý tưởng những gì tôi đang làm sai?

Câu trả lời:


147

Cách tốt nhất mà tôi đã tìm thấy để đạt được điều này là sử dụng Bộ nhận dạng cử chỉ. Các cách khác hóa ra lại liên quan đến nhiều chương trình hack sao chép mã của Apple một cách không hoàn hảo, đặc biệt là trong trường hợp cảm ứng đa điểm.

Đây là những gì tôi làm: Triển khai trình nhận dạng cử chỉ không thể bị ngăn chặn và không thể ngăn chặn các trình nhận dạng cử chỉ khác. Thêm nó vào chế độ xem bản đồ, sau đó sử dụng các cử chỉ TouchBegan, touchMoved, v.v. của cử chỉ theo sở thích của bạn.

Cách phát hiện bất kỳ lần nhấn nào bên trong MKMapView (không có thủ thuật)

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" để làm gì?
jowie

đó là một biến không liên quan cụ thể cho ứng dụng của tôi. nó theo dõi liệu hệ thống có nên tự động căn giữa bản đồ vào vị trí hiện tại hay không
gonzojive

Đây là giải pháp hoàn hảo. Tôi cần làm rõ một điều: Trong phương thức "- (void) touchBegan: (NSSet *) touch withEvent: (UIEvent *) event", mục đích của việc sử dụng mã là gì: if (touchBeganCallback) touchBeganCallback (touch, event);
Satyam

1
Điều này hoạt động tốt cho hầu hết các phần nhưng tôi đã tìm thấy một vấn đề với nó. Nếu HTML trong chế độ xem web của bạn chứa videothẻ HTML5 với các điều khiển, thì trình nhận dạng cử chỉ sẽ ngăn người dùng không thể sử dụng các điều khiển. Tôi đã tìm kiếm một giải pháp cho vấn đề này nhưng vẫn chưa tìm thấy một giải pháp nào.
Bryan Irace

Cảm ơn bạn đã chia sẻ. Tại sao không có phương pháp ủy quyền phù hợp để theo dõi tương tác của người dùng với chế độ xem bản đồ, tôi không nghĩ nhưng điều này hoạt động tốt.
Justin Driscoll

29

Sau một ngày ăn pizza, la hét, cuối cùng tôi đã tìm ra giải pháp! Rât gọn gang!

Peter, tôi đã sử dụng thủ thuật của bạn ở trên và chỉnh sửa nó một chút để cuối cùng có một giải pháp hoạt động hoàn hảo với MKMapView và cũng sẽ hoạt động với 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

Tôi hy vọng rằng sẽ giúp một số bạn!

Chúc mừng


14
Đẹp. Gợi ý nhỏ: Bạn nên tránh đặt tên các lớp của riêng mình bằng tiền tố giao diện người dùng. Apple bảo lưu / không khuyến khích sử dụng NS hoặc UI làm tiền tố lớp, vì những thứ này có thể dẫn đến xung đột với lớp Apple (ngay cả khi đó là lớp riêng).
Daniel Dickison

Này Daniel, Bạn hoàn toàn đúng, tôi cũng nghĩ vậy! Để hoàn thành câu trả lời của tôi ở trên, hãy để tôi thêm một cảnh báo nhỏ: Ví dụ của tôi giả sử chỉ có một đối tượng viewTouched, đang sử dụng tất cả các sự kiện. Nhưng điều đó không đúng. Bạn có thể có một số Chú thích trên Bản đồ của mình và sau đó mã của tôi không hoạt động nữa. Để hoạt động 100%, bạn cần nhớ cho mỗi lần truy cập Kiểm tra chế độ xem được liên kết với sự kiện cụ thể đó (và cuối cùng giải phóng nó khi kích hoạt touchEnded hoặc touchCancell để bạn không cần theo dõi các sự kiện đã kết thúc ...).
Martin

1
Mã rất hữu ích, cảm ơn Martin! Tôi đã tự hỏi liệu bạn có thử thu phóng bản đồ sau khi thực hiện điều này không? Đối với tôi khi tôi làm cho nó hoạt động về cơ bản bằng cách sử dụng cùng một đoạn mã mà bạn có ở trên, mọi thứ dường như hoạt động ngoại trừ việc chụm để phóng to bản đồ. Ai có ý tưởng gì không?
Adam Alexander

Này Adam, tôi cũng có hạn chế này và tôi thực sự không hiểu tại sao! Điều đó thực sự là khó chịu. Nếu bạn tìm thấy một giải pháp, hãy cho tôi biết! Thx
Martin

Ok, tôi đã bình chọn cái này vì nó ban đầu có vẻ giải quyết được vấn đề của tôi. TUY NHIÊN...! Tôi dường như không thể sử dụng cảm ứng đa điểm để hoạt động. Có nghĩa là, ngay cả khi tôi trực tiếp chuyển các lần chạm vàoBegan và chạm vào Đã xóa để xem Đã chạm (tôi thực hiện thao tác chặn khi chạm vào Đã chạm), tôi không thể thu phóng bản đồ bằng các cử chỉ chụm. (Còn tiếp ...)
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
Tôi không chắc tại sao đây không phải là câu trả lời hàng đầu. Có vẻ hoạt động hoàn hảo, và đơn giản hơn nhiều.
elsurudo

12

Đối với MKMapView, giải pháp hoạt động thực sự là nhận dạng cử chỉ!

Tôi Tôi muốn dừng cập nhật tâm bản đồ về vị trí của mình khi tôi kéo bản đồ hoặc chụm để thu phóng.

Vì vậy, hãy tạo và thêm trình nhận dạng cử chỉ của bạn vào 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];
}

Xem Tham chiếu Lớp UIGestureRecognizer để xem tất cả các trình nhận dạng cử chỉ có sẵn.

Bởi vì chúng tôi đã xác định ủy quyền cho chính mình, chúng tôi phải triển khai 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;
...

Và ghi đè cử chỉ methode: cử chỉ cử chỉ nênRecognizeSim ngần ấyWithGestureRecognizer: để cho phép nhận ra nhiều cử chỉ đồng thời, nếu tôi hiểu đúng:

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

Bây giờ viết các phương thức sẽ được gọi bởi các trình nhận dạng cử chỉ của chúng tôi:

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

Giải pháp này là hoàn hảo! Một số tính năng nhanh ở đây: Nếu bạn muốn chặn khi người dùng kết thúc thực hiện bất kỳ hành động nào bằng cách sử dụng tính năng này thì nên lưu ý - (void) handleLongPressAndPinchGesture: (UIGestureRecognizer *) sender {if (sender.state == UIGestureRecognizerStateEnded) {NSLog (@ "handleLongPressAndPinch) ; }}
Alejandro Luengo

Cũng đừng quên thêm đại biểu <UIGestureRecognizerDelegate>
Alejandro Luengo

6

Đề phòng trường hợp ai đó đang cố gắng làm như tôi: Tôi muốn tạo chú thích tại điểm người dùng chạm vào. Đối với điều đó, tôi đã sử dụng UITapGestureRecognizergiải pháp:

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

Tuy nhiên, didTapOnMap:nó cũng được gọi khi tôi nhấn vào chú thích và một chú thích mới sẽ được tạo. Giải pháp là thực hiện UIGestureRecognizerDelegate:

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

Đây là một giải pháp tuyệt vời! Nhưng nó không hoạt động nếu bạn sử dụng chế độ xem tùy chỉnh dưới dạng MKAnnotation. Trong trường hợp này, bạn có thể có chế độ xem phụ của chú thích khác kích hoạt trình nhận dạng cử chỉ. Tôi phải kiểm tra một cách đệ quy superview của touch.view để tìm một MKAnnotationView tiềm năng
KIDdAe

3

Bạn có thể sẽ cần phải phủ một chế độ xem trong suốt để nắm bắt các thao tác giống như được thực hiện thường xuyên với các điều khiển dựa trên UIWebView. Chế độ xem Bản đồ đã thực hiện một loạt những điều đặc biệt chỉ với một lần chạm để cho phép bản đồ được di chuyển, căn giữa, thu phóng, v.v ... mà các thông báo không được đưa vào ứng dụng của bạn.

Hai tùy chọn (UNTESTED) khác mà tôi có thể nghĩ đến:

1) Chỉ định người phản hồi đầu tiên qua IB và đặt nó thành "Chủ sở hữu tệp" để cho phép Chủ sở hữu tệp phản hồi các thao tác. Tôi nghi ngờ rằng điều này sẽ hoạt động vì MKMapView mở rộng NSObject, không phải UIView dẫn đến kết quả là các sự kiện cảm ứng vẫn có thể không được truyền tải đến bạn.

2) Nếu bạn muốn bẫy khi trạng thái Bản đồ thay đổi (chẳng hạn như khi thu phóng), chỉ cần triển khai giao thức MKMapViewDelegate để lắng nghe các sự kiện cụ thể. Linh cảm của tôi là đây là cách tốt nhất để bạn dễ dàng bẫy được một số tương tác (ngắn gọn của việc triển khai Chế độ xem trong suốt trên Bản đồ). Đừng quên đặt Bộ điều khiển Chế độ xem chứa MKMapView làm đại biểu của bản đồ ( map.delegate = self).

Chúc may mắn.


MKMapView chắc chắn phân lớp UIView.
Daniel Dickison

2

Tôi chưa thử nghiệm, nhưng có nhiều khả năng MapKit dựa trên một cụm lớp và do đó việc phân lớp con rất khó và không hiệu quả.

Tôi khuyên bạn nên đặt chế độ xem MapKit làm chế độ xem phụ của chế độ xem tùy chỉnh, điều này sẽ cho phép bạn chặn các sự kiện chạm trước khi chúng tiếp cận nó.


Xin chào Graham! Cảm ơn sự giúp đỡ của bạn! Nếu tôi tạo chế độ xem siêu tùy chỉnh như bạn đề xuất, thì làm cách nào để chuyển tiếp các sự kiện đến MKMapView? Bất kỳ ý tưởng?
Martin

2

Vì vậy, sau nửa ngày lộn xộn với điều này, tôi đã tìm thấy những điều sau:

  1. Như những người khác đã tìm thấy, tính năng chụm không hoạt động. Tôi đã thử cả phân lớp MKMapView và phương pháp được mô tả ở trên (chặn nó). Và kết quả là như nhau.
  2. Trong video về iPhone của Stanford, một anh chàng đến từ Apple nói rằng nhiều thứ trong UIKit sẽ gây ra rất nhiều lỗi nếu bạn "chuyển" các yêu cầu cảm ứng (hay còn gọi là hai phương pháp được mô tả ở trên) và có thể bạn sẽ không hoạt động được.

  3. GIẢI PHÁP : được mô tả ở đây: Sự kiện chặn / chiếm quyền điều khiển iPhone Touch cho MKMapView . Về cơ bản, bạn "nắm bắt" sự kiện trước khi bất kỳ người phản hồi nào nhận được nó và diễn giải nó ở đó.


2

Trong 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

Đặt MKMapView làm chế độ xem phụ của chế độ xem tùy chỉnh và triển khai

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

trong chế độ xem tùy chỉnh để trả về bản thân thay vì chế độ xem phụ.


Xin chào Peter, Cảm ơn câu trả lời của bạn! Nhưng tôi nghĩ rằng bằng cách đó, MKMapView có thể không nhận được bất kỳ sự kiện chạm vào nào, phải không? Tôi đang tìm một cách để chỉ bắt sự kiện và sau đó chuyển tiếp nó đến MKMapView.
Martin

0

Cảm ơn vì chiếc bánh pizza và những món ăn khoái khẩu - bạn đã tiết kiệm cho tôi rất nhiều thời gian.

multitouchenabled sẽ hoạt động không thường xuyên.

viewTouch.multipleTouchEnabled = TRUE;

Cuối cùng, tôi đã chuyển đổi các chế độ xem khi tôi cần chụp liên lạc (khác với thời điểm cần thu nhỏ):

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

nhưng không hoạt động với tính năng phóng to trực tiếp. Nó cũng dường như luôn luôn thu nhỏ.
Rog

0

Tôi nhận thấy rằng bạn có thể theo dõi số lượng và vị trí của các lần chạm và nhận vị trí của mỗi lần chạm trong một chế độ xem:

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

Có ai khác đã thử sử dụng các giá trị này để cập nhật mức thu phóng của bản đồ không? Nó sẽ là vấn đề ghi lại các vị trí bắt đầu và sau đó là các vị trí kết thúc, tính toán sự khác biệt tương đối và cập nhật bản đồ.

Tôi đang chơi với mã cơ bản do Martin cung cấp và điều này có vẻ như nó sẽ hoạt động ...


0

Đây là những gì tôi tổng hợp lại, điều đó cho phép phóng to thu nhỏ trong trình mô phỏng (chưa thử trên iPhone thực), nhưng tôi nghĩ sẽ ổn:

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

Ý tưởng chính là nếu người dùng đang sử dụng hai ngón tay, bạn sẽ theo dõi các giá trị. Tôi ghi lại điểm bắt đầu và điểm kết thúc trong startPoints A và B. Sau đó, tôi ghi lại các điểm theo dõi hiện tại và khi tôi hoàn thành, trên touchEnded, tôi có thể gọi một quy trình để tính toán độ dài tương đối của đường giữa các điểm mà tôi bắt đầu. , và đường giữa điểm tôi kết thúc bằng cách sử dụng hàm cạnh huyền đơn giản. Tỷ lệ giữa chúng là số lượng thu phóng: Tôi nhân khoảng vùng với số lượng đó.

Hy vọng nó hữu ích cho ai đó.


0

Tôi lấy ý tưởng về chế độ xem trong suốt "lớp phủ", từ câu trả lời của MystikSpiral, và nó hoạt động hoàn hảo cho những gì tôi đang cố gắng đạt được; giải pháp nhanh chóng và sạch sẽ.

Nói tóm lại, tôi đã có một UITableViewCell tùy chỉnh (được thiết kế bằng IB) với MKMapView ở phía bên trái và một số UILabels ở bên phải. Tôi muốn tạo ô tùy chỉnh để bạn có thể chạm vào nó ở bất kỳ đâu và điều này sẽ tạo ra một bộ điều khiển chế độ xem mới. Tuy nhiên, việc chạm vào bản đồ đã không vượt qua các lần chạm 'lên' UITableViewCell cho đến khi tôi chỉ cần thêm một UIView có cùng kích thước với chế độ xem bản đồ ngay trên nó (trong IB) và làm cho nền của nó là 'màu rõ ràng' trong mã ( đừng nghĩ rằng bạn có thể đặt clearColor trong IB ??):

dummyView.backgroundColor = [UIColor clearColor];

Nghĩ rằng nó có thể giúp ích cho người khác; chắc chắn nếu bạn muốn đạt được hành vi tương tự cho một ô xem bảng.


"Tuy nhiên, việc chạm vào bản đồ không vượt qua được các lần chạm 'lên' UITableViewCell cho đến khi tôi chỉ cần thêm một UIView có cùng kích thước với chế độ xem bản đồ ngay trên nó" Điều này không đúng. Bản đồ đang xử lý các lần chạm vì nó có các tương tác của riêng người dùng, chẳng hạn như cuộn, v.v. Nếu bạn muốn phát hiện mặc dù trên ô thay vì tương tác với bản đồ, chỉ cần đặt map.isUserInteractionEnabled = false Sau đó, bạn có thể chỉ cần sử dụng didSelectRowAtIndexPath trong bảng xem đại biểu.
BROK3N S0UL
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.