6

3.0 SDK にバグがあり、リアルタイムのズームが無効になり、MKMapView のズームイン ジェスチャがインターセプトされますか? タップイベントを検出できるように、本当に単純なコードがいくつかありますが、2 つの問題があります。

  1. ズームイン ジェスチャは常にズームアウトとして解釈されます
  2. ズーム ジェスチャはどれも、マップのビューをリアルタイムで更新しません。

hitTest で「マップ」ビューを返すと、MKMapView 機能はうまく機能しますが、イベントをインターセプトする機会がありません。

何か案は?

MyMapView.h:

@interface MyMapView : MKMapView
{
    UIView      *map;
}

MyMapView.m:

- (id)initWithFrame:(CGRect)frame
{
    if (![super initWithFrame:frame])
        return nil;

    self.multipleTouchEnabled = true;

    return self;
}

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    NSLog(@"Hit Test");
    map = [super hitTest:point withEvent:event];
    return self;
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"%s", __FUNCTION__);
    [map touchesCancelled:touches withEvent:event];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent*)event
{
    NSLog(@"%s", __FUNCTION__);
    [map touchesBegan:touches withEvent:event];
}

- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
    NSLog(@"%s, %x", __FUNCTION__, mViewTouched);
    [map touchesMoved:touches withEvent:event];
}

- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{
    NSLog(@"%s, %x", __FUNCTION__, mViewTouched);
    [map touchesEnded:touches withEvent:event];
}
4

6 に答える 6

8

これを達成するために私が見つけた最良の方法は、Gesture Recognizer を使用することです。ズームイベントを自分で認識したいのか、ユーザーがズーム/パンしているときを検出したいだけなのかは不明です。

マップのパンやズームを検出する必要はありません。ユーザーが MKMapView のどこかに指を置いたかどうかを気にするだけです。100% の再現率と精度でズームまたはパンを検出する必要がある場合は、これよりも複雑になる可能性があります。本当に必要なのは、MKMapView のオープン ソース実装であり、他の多くの機能の中でもデリゲートにこれを追加できます。

私がやっていることは次のとおりです: 防ぐことができず、他のジェスチャ レコグナイザーを防ぐことができないジェスチャ レコグナイザーを実装します。それをマップ ビューに追加し、必要に応じて関連するタッチ イベントを処理します。

MKMapView 内のタップを検出する方法 (sans トリック)

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
于 2010-10-31T18:53:25.960 に答える
5

私は同じ問題を抱えていました.Map Viewの上に地図縮尺を描きたかったのです。これを行うには、タッチ イベントをインターセプトし、それらをマップ ビューに送り返す必要がありました。残念ながら、MKMapView がイベントの元のレシーバーではない場合、スムーズなパンとズームのアニメーションが機能しなくなります。

しかし、私はこの問題の解決策を見つけました - 少しハックですが動作します: 1. MapScales UIView を MKMapView の上に置き、イベントの受信をオフにして、基礎となる MKMapView がデフォルトでイベントを受信するようにしました。2. UIWindow を MyMainWindow クラスでサブクラス化し、その中でメソッドをオーバーライドしました。

- (void) sendEvent:(UIEvent*)event {
  [super sendEvent:event];
  [self send_the_event_also_to_my_MapScales_component_with_use_of_listener_design_pattern];
}
  1. アプリケーションのメイン ウィンドウを MyMainWindow のインスタンスにしました。

このようにして、私のMapScalesコンポーネントはすべてのタッチイベントを受け取り、反応することができ、同時に基礎となるMKMapViewを損なうことはありません:)

于 2009-09-05T13:55:06.507 に答える
2
#import <UIKit/UIKit.h>
#import "UIViewTouch.h"
#import <MapKit/MapKit.h>

@interface MapTouchAppDelegate : NSObject <UIApplicationDelegate>
{
    UIViewTouch *viewTouch;
    MKMapView *mapView;
    UIWindow *window;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) UIViewTouch *viewTouch;
@property (nonatomic, retain) MKMapView *mapView;

@end


#import "MapTouchAppDelegate.h"

@implementation MapTouchAppDelegate

@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];
    // Override point for customization after application launch
    [window makeKeyAndVisible];
}


- (void)dealloc {
    [window release];
    [super dealloc];
}

#import <UIKit/UIKit.h>


@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


#import "UIViewTouch.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");
    self.multipleTouchEnabled = true;
    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

このコードは、タッチとズームを検出します。

于 2010-09-16T07:45:16.010 に答える
1

@chomasekの回答を拡張するには、マップビューのタッチのみを処理するために、次のことを行います。

  1. マップ ビューに 99 などのタグを付けます
  2. 触ったら、受け取ったビューのビュー階層をたどり、上記のタグを持つビューを探します。

コードは次のとおりです。

// this is in the view controller containing the map view
// kICTagForMapView is just a constant
_mapView.tag = kICTagForMapView;

次にsendEvent:

// this does into the UIWindow subclass
BOOL isMapView = NO;    
UIView* superView = touch.view.superview;
while(superView)
{
    //Debug(@"superView = %@", superView);
    if (superView.tag == kICTagForMapView)
    {
        isMapView = YES;
        break;
    }
    superView = superView.superview;
}

if (isMapView == NO) return;

// do stuff here
于 2010-05-09T08:43:49.813 に答える
1

試す

[super touchesEnded:touches withEvent:event];

それ以外の

[map touchesEnded:touches withEvent:event];

そして、この考え方をすべてのタッチ イベント メソッドに適用します。そうすれば、タッチはレスポンダー チェーンを下って移動し、平和が回復します。

于 2009-08-19T07:38:04.713 に答える
0

MKMapView は、上記のタッチ方法に応答しません...

于 2009-07-13T21:09:03.503 に答える