3

私のインターフェイスには、その周辺にボタンが配置されていることがあります。ボタンのない領域はジェスチャーを受け入れます。

GestureRecognizer は、viewDidLoad でコンテナー ビューに追加されます。以下に、tapGR のセットアップ方法を示します。

UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(playerReceived_Tap:)];
[tapGR setDelegate:self];
[self.view addGestureRecognizer:tapGR];

ジェスチャ レコグナイザーがボタン タップを傍受するのを防ぐために、タッチされたビューがボタンでない場合にのみ YES を返すように shouldReceiveTouch を実装しました。

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gr 
   shouldReceiveTouch:(UITouch *)touch {

    // Get the topmost view that contains the point where the gesture started.
    // (Buttons are topmost, so if they were touched, they will be returned as viewTouched.)
    CGPoint pointPressed = [touch locationInView:self.view];
    UIView *viewTouched = [self.view hitTest:pointPressed withEvent:nil];

    // If that topmost view is a button, the GR should not take this touch.
    if ([viewTouched isKindOfClass:[UIButton class]])
        return NO;

    return YES;

}

ほとんどの場合、これで問題なく動作しますが、反応しないボタンがいくつかあります。これらのボタンがタップされると、hitTest はボタンではなくコンテナー ビューを返すため、shouldReceiveTouch は YES を返し、gestureRecognizer はイベントを指揮します。

デバッグするために、いくつかのテストを実行しました...

次のテストでは、ボタンがコンテナー ビューのサブサブビューであること、有効であること、およびボタンとサブビューの両方が userInteractionEnabled であることを確認しました。

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gr 
   shouldReceiveTouch:(UITouch *)touch {

// Test that hierarchy is as expected: containerView > vTop_land > btnSkipFwd_land.
for (UIView *subview in self.view.subviews) {
    if ([subview isEqual:self.playComposer.vTop_land])
        printf("\nViewTopLand is a subview."); // this prints
}
for (UIView *subview in self.playComposer.vTop_land.subviews) {
    if ([subview isEqual:self.playComposer.btnSkipFwd_land])
        printf("\nBtnSkipFwd is a subview."); // this prints
}

// Test that problem button is enabled.
printf(“\nbtnSkipFwd enabled? %d", self.playComposer.btnSkipFwd_land.enabled); // prints 1

// Test that all views in hierarchy are interaction-enabled.
printf("\nvTopLand interactionenabled? %d", self.playComposer.vTop_land.userInteractionEnabled); // prints 1
printf(“\nbtnSkipFwd interactionenabled? %d", self.playComposer.btnSkipFwd_land.userInteractionEnabled); // prints 1

// etc

}

次のテストでは、押されたポイントが実際にボタンのフレーム内にあることを確認します。

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gr 
   shouldReceiveTouch:(UITouch *)touch {

CGPoint pointPressed = [touch locationInView:self.view];
CGRect rectSkpFwd = self.playComposer.btnSkipFwd_land.frame;

// Get the pointPressed relative to the button's frame.
CGPoint pointRelSkpFwd = CGPointMake(pointPressed.x - rectSkpFwd.origin.x, pointPressed.y - rectSkpFwd.origin.y);
printf("\nIs relative point inside skipfwd? %d.", [self.playComposer.btnSkipFwd_land pointInside:pointRelSkpFwd withEvent:nil]); // prints 1

// etc

}

では、なぜ hitTest はこのボタンではなくコンテナ ビューを返すのでしょうか?

解決策: 私がテストしなかったことの 1 つは、中間ビュー vTop_land が適切にフレーム化されていることでした。フレームの境界を超えて画面全体に広がる画像があったため、問題ないように見えました(これが可能であることは知りませんでした)。フレームは横幅ではなく縦幅に設定されていたため、右端のボタンは範囲外でした。

4

1 に答える 1