2010-11-29 15 views
12

私はアプリケーション全体で発生するアクティビティ(つまり接触)を傍受しようとしています。UIViewの-hitTest:withEvent:3回呼び出されましたか?

つまり、残りのコントロールを含む、メインUIView内で発生するタッチイベントの通知を受けようとしています。 これを行うには、UIViewのメソッド-hitTest:withEvent:が良い解決策であると思っていました。

しかし、[super hitTest:... withEvent:...]を呼び出す前にこのオーバーライドされたメソッドにNSLogを書き込むと、私はそれを3回呼び出していることがわかります。それが呼び出されるたびに私が受け取るイベントです。ここで

は自分のアプリケーションのメインビューでメソッドを実装する方法である:どのように私でし

2010-11-29 14:09:26.892 Application[68818:207] hitTest:withEvent called : 
2010-11-29 14:09:26.892 Application[68818:207] Event: <UITouchesEvent: 0x5716d60> timestamp: 37935.2 touches: {(
)} 
2010-11-29 14:09:26.892 Application[68818:207] Point: {173, 498} 
2010-11-29 14:09:26.892 Application[68818:207] Event Type: 0 
2010-11-29 14:09:26.892 Application[68818:207] Event SubType: 0 
2010-11-29 14:09:26.893 Application[68818:207] --- 
2010-11-29 14:09:26.893 Application[68818:207] hitTest:withEvent called : 
2010-11-29 14:09:26.893 Application[68818:207] Event: <UITouchesEvent: 0x5716d60> timestamp: 37935.2 touches: {(
)} 
2010-11-29 14:09:26.893 Application[68818:207] Point: {173, 498} 
2010-11-29 14:09:26.893 Application[68818:207] Event Type: 0 
2010-11-29 14:09:26.893 Application[68818:207] Event SubType: 0 
2010-11-29 14:09:26.893 Application[68818:207] --- 
2010-11-29 14:09:26.893 Application[68818:207] hitTest:withEvent called : 
2010-11-29 14:09:26.894 Application[68818:207] Event: <UITouchesEvent: 0x5716d60> timestamp: 37944.9 touches: {(
)} 
2010-11-29 14:09:26.894 Application[68818:207] Point: {173, 498} 
2010-11-29 14:09:26.894 Application[68818:207] Event Type: 0 
2010-11-29 14:09:26.894 Application[68818:207] Event SubType: 0 
2010-11-29 14:09:26.894 Application[68818:207] --- 

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 
{ 
    NSLog(@"hitTest:withEvent called :"); 
    NSLog(@"Event: %@", event); 
    NSLog(@"Point: %@", NSStringFromCGPoint(point)); 
    NSLog(@"Event Type: %d", event.type); 
    NSLog(@"Event SubType: %d", event.subtype); 
    NSLog(@"---"); 

    return [super hitTest:point withEvent:event]; 
} 

そして、ここではどのような私は、このビューでは、単一のタッチのためのNSLogですワンタッチで1回だけ実行したいアクションをトリガするために、これらの3つの通知の間に違いがありますか?

ありがとうございます!

+0

ここまできれいな解決策が見つかりましたか?私は同じ問題を抱えている。勤怠集計はうまくいくと思われますが、将来はSDKの変更が容易に起きる可能性があります。 –

+0

これはなぜ起こるのでしょうか?私は自分自身でこれを理解しようとしています – prostock

+0

この問題について進歩はありますか? –

答えて

2

表示されるイベント応答の数は、ビュー階層によって異なります。 withEvent:メッセージをタッチイベントを受信すべき をサブビュー決定するために、各 サブビューに

この方法は pointInsideを送信することによって、図 階層を横断します。 pointInside:withEvent:YES、 を返した場合、サブビューの階層は です。そうでない場合は、ビュー階層の のブランチは無視されます。 はこのメソッドを自分で と呼ぶ必要はほとんどありませんが、サブビューからタッチイベントを非表示にするには にオーバーライドすることができます。

が非表示になっているか、ユーザー が無効になっているか、アルファレベルが で0.01未満のビューオブジェクトは無視されます。この方法では、ヒットを判定するときに ビューのコンテンツをアカウント に持っていません。したがって、 のビューは、 指定されたポイントがそのビューの内容の透明な 部分にある場合でも、依然として返されます。レシーバの 境界の外にある

ポイントは、彼らが実際に受信機のサブビューの1 内にある場合でも 、ヒットとして報告されることはありません。現在のビューの clipsToBoundsプロパティがNO に設定されていて、影響を受けるサブビューがビューの境界を超えて に及ぶ場合、これは になります。

UIView Class Referenceより。

簡単に言えば、タッチしたビューに3つのサブビューがあり、そのビューがスーパービューとタッチ領域の境界内に表示されている場合、3回のヒットテスト応答が表示されます。

+1

メインビューには3つ以上のサブビューが含まれているため、3つ以上の応答を受け取らないようにしてください。また、1つのビューのみを含む新しいプロジェクトで同じテストを行うと、まったく同じ結果が得られます。 –

+0

シミュレータまたは実際のデバイスを使用していますか? –

+0

Hmmm ..私はシミュレータでのみテストしました。私は実際のデバイスで試して、あなたに戻ってきます –

10

実際にhitTestを3回呼び出しています。理由は明らかではありませんが、最初の2回の呼び出しが以前のジェスチャーを完了することと関係がある場合、タイムスタンプで推測することができます。これらのタイムスタンプは、以前のタッチが発生したときはいつも非常に近く、現在の時刻。

これは私がプロセスにhitTestを決定する方法である:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { 
    NSTimeInterval system = [[NSProcessInfo processInfo] systemUptime]; 

    if (system - event.timestamp > 0.1) { 
    // not the event we were interested in 
    } else { 
    // use this call 
    } 
} 
+1

はちょっとハッキリですが、うまくいきます:) –

7

これはあなたのためにまだ問題がある場合。

このトピックに関するいくつかの例と議論がありましたが、適切な解決策は非常に簡単です。

一般に、hittestはUIViewまたはUIScrollView内で3回呼び出されます。これはビュー階層を横断した結果です。

非常に簡単で、私にとっては、常に適切な解決策は以下のとおりです。

あなたは私のため

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

を実装ビューで関数hittestを実装する - すべての3つの関数呼び出しは常に同じ位置を持っている - これだけ場所をローカルクラスに格納します。 .hファイルで

:.mファイル

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{ 
    return [super hitTest:point withEvent:event]; 
} 

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{ 
// The point check you need  
    if(point.y != self.touchLocation.y){ 
     touchLocation_ = point; 
    // The function call you need - just called once. 
    } 
    return [super pointInside:point withEvent:event]; 
} 

この溶液中の

@interface MyScrollView : UIScrollView { 
    CGPoint touchLocation_; 
} 

@property (nonatomic, readonly) CGPoint touchLocation; 

は非常によく、いくつかのプロジェクトで私のために動作します。

関連する問題