【问题标题】:Some buttons fail hitTest某些按钮未通过 hitTest
【发布时间】:2013-04-11 23:19:32
【问题描述】:

我的界面有时周围有按钮。没有按钮的区域接受手势。

GestureRecognizers 被添加到容器视图中,在 viewDidLoad 中。以下是 tapGR 的设置方式:

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

为了防止手势识别器拦截按钮点击,我实现了 shouldReceiveTouch 以仅在触摸的视图不是按钮时返回 YES:

- (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 返回的是容器视图而不是这个按钮呢?

解决方案:我没有测试的一件事是中间视图 vTop_land 的构图正确。它看起来不错,因为它的图像延伸到屏幕上——超出了框架的边界(我不知道这是可能的)。框架设置为纵向宽度,而不是横向宽度,因此最右侧的按钮超出区域。

【问题讨论】:

    标签: ios objective-c uigesturerecognizer hittest


    【解决方案1】:

    命中测试在大多数情况下并不可靠,通常不建议将其与手势识别器一起使用。

    你为什么不为每个按钮setExclusiveTouch:YES,这应该确保按钮总是被选中。

    【讨论】:

    • 我喜欢这个主意。这听起来比我正在做的更有效率。目前,由于其他问题,该按钮仍未响应,但...
    • 我已将此标记为已接受的答案,因为该建议非常好。我在问题的底部添加了实际的解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-24
    • 2016-01-11
    • 1970-01-01
    • 1970-01-01
    • 2012-05-15
    • 1970-01-01
    • 2021-06-27
    相关资源
    最近更新 更多