UIScrollView触及子视图触摸

时间:2009-05-18 13:47:53

标签: iphone objective-c cocoa-touch uiscrollview

请有人帮忙排序一个菜鸟吗?我已经在各种论坛上发布了这个问题并且没有得到任何答案,而许多搜索其他答案已经发现了stackOverflow,所以我希望这就是这个地方。

我有一个BeachView.h(UIScrollView的子类,沙滩的图片),上面覆盖着一个随机数的Stone.h(UIImageView的子类,一个石头的随机PNG,userInteractionEnabled = YES接受触摸)

如果用户触摸并在海滩上移动,则应滚动。 如果用户点击一块石头,它应该调用方法“touchingStone”。 如果用户点击没有石头的海滩,则应该调用方法“touchBeach”。

现在,我意识到这听起来很简单。每个人和每件事都告诉我,如果UIScrollView上有某些东西接受它应该将控制传递给它的触摸。所以当我触摸并拖动时,它应该滚动;但如果我点击它,它在石头上,它应该忽略海滩水龙头并接受石头水龙头,是吗?

但是,似乎两个视图都接受了点击并调用了touchStone和touchingBeach。此外,沙滩水龙头首先发生,所以我甚至不能放入“如果触摸石头然后不运行touchBeach”类型的标志。

这是一些代码。 在BeachView.m


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
     if (self.decelerating) { didScroll = YES; }
        else { didScroll = NO; }

     UITouch *touch = [[event allTouches] anyObject];
     CGPoint touchLocation = [touch locationInView:touch.view];
     NSLog(@"touched beach = %@", [touch view]);
     lastTouch = touchLocation;
     [super touchesBegan:touches withEvent:event];
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
     didScroll = YES;
     [super touchesMoved:touches withEvent:event];
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
     if (didScroll == NO && isPaused == NO) { 
          [self touchedBeach:YES location:lastTouch];
     }
     [super touchesEnded:touches withEvent:event];
}

On Stone.m


-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
     [parent stoneWasTouched]; // parent = ivar pointing from stone to beachview
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
     UITouch *touch = [[event allTouches] anyObject];
     CGPoint touchLocation = [touch locationInView:touch.view];
     NSLog(@"touched stone = %@", [touch view]);
     [parent touchedStone:YES location:touchLocation];
}

在点击之后,我的NSLog看起来像这样:


Touched beach = <BeachView: 0x1276a0>
ran touchedBeach
Touched Stone = <Stone: 0x1480c0>
ran touchedStone

所以它实际上都在运行。更奇怪的是,如果我将touchesBegan和touchesEnded从Stone.m中删除但是留下userInteractionEnabled = YES,则beachView寄存器会自动触摸,但会返回Stone作为其触摸的视图(第二次)。


Touched beach = <BeachView: 0x1276a0>
ran touchedBeach
Touched beach = <Stone: 0x1480c0>
ran touchedBeach

所以,请问,我一直试图对此进行分类。我如何制作这样一个敲击的石头只调用触摸的石头和一个轻拍的海滩叫只触摸了海滩?我哪里错了?

4 个答案:

答案 0 :(得分:3)

是的,iPhone SDK 3.0及更高版本,不再向-touchesBegan:和 - touchesEnded: ** UIScrollview **子类方法传递触摸。您可以使用不同的touchesShouldBegintouchesShouldCancelInContentView方法。

如果你真的想要接触这个,请有一个允许这样做的 hack

UIScrollView的子类中,覆盖hitTest方法,如下所示:

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

  UIView *result = nil;
  for (UIView *child in self.subviews)
    if ([child pointInside:point withEvent:event])
      if ((result = [child hitTest:point withEvent:event]) != nil)
        break;

  return result;
}

这将传递给你这个触摸的子类,但是你不能取消对UIScrollView超类的触摸。

答案 1 :(得分:2)

在iPhone OS 3.0之前,UIScrollView的hitTest:withEvent:方法总是返回self,以便它直接接收UIEvent,只有当它确定它与滚动或缩放无关时才将其转发到适当的子视图。

我无法真正评论iPhone OS 3.0,因为它是在NDA下,但请查看“适用于iPhone OS 3.0 beta 5的iPhone SDK发行说明”:)

如果你需要定位3.0之前的版本,你可以在BeachView中覆盖hitTest:withEvent:并设置一个标志,如果CGPoint实际上是一块石头,则忽略下一个海滩触摸。

但你是否尝试过将你的调用从你被覆盖的方法的结尾移动到[super touches *:withEvent:]到开始?这可能会导致石头敲击。

答案 2 :(得分:0)

simpleView我遇到了类似的问题,并将其添加到scrollView,每当我触及simpleView时,scrollView过去就会触及而不是simpleView,scrollView移动了。为避免这种情况,我在用户触摸scrollView时禁用了simpleView的srcolling,否则启用了滚动功能。

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

    UIView *result = [super hitTest:point withEvent:event] ;
    if (result == simpleView)
    {
        scrollView.scrollEnabled = NO ;
    }
    else
    {
        scrollView.scrollEnabled = YES ;
    }

    return result ;

}

答案 3 :(得分:0)

这可能与iOS7中的错误相关,请查看我的问题(提交错误报告)

UIScrollView subclass has changed behavior in iOS7

相关问题