【问题标题】:UIScrollView touches vs subview touchesUIScrollView 触摸与子视图触摸
【发布时间】:2009-05-18 13:47:53
【问题描述】:

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

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

如果用户在海滩上触摸和移动,它应该滚动。 如果用户点击石头,它应该调用方法“touchedStone”。 如果用户点击没有石头的海滩,它应该调用方法“touchedBeach”。

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

但是,似乎两个视图都接受了点击并调用了touchedStone 和touchedBeach。此外,海滩水龙头首先发生,所以我什至不能输入“如果接触石头,则不要运行接触海滩”类型的标志。

这里有一些代码。 在 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];
}

在石头上.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

所以请,我这几天一直在努力解决这个问题。我怎样才能使敲击的石头只调用touchedStone,而敲击的海滩只调用touchedBeach?我哪里错了?

【问题讨论】:

    标签: iphone objective-c cocoa-touch uiscrollview


    【解决方案1】:

    是的,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 超类的触摸。

    【讨论】:

      【解决方案2】:

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

      我无法对 iPhone OS 3.0 发表评论,因为它在 NDA 下,但请查看您的“iPhone SDK Release notes for iPhone OS 3.0 beta 5”:)

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

      但是您是否尝试过简单地将对 [super touches*:withEvent:] 的调用从覆盖方法的末尾移到开头?这可能会导致先敲击石头。

      【讨论】:

      • 我将 [super] 移到了方法的开头,它有所作为。它仍然记录了两个水龙头,但至少现在它说 1-beganBeach 2-beganStone 3-endedBeach 4-endedStone,所以有时间在那里弹出一个标志。我只是在看hitTest,但是当它开始谈论CAlayers vs UIviews时,它看起来像是一本我还没准备好打开的书。我再试一次。谢谢哈特芬奇,-k。
      【解决方案3】:

      simpleView 有类似的问题,它被添加到 scrollView 中,每当我触摸 simpleView 时,scrollView 用于获得触摸,而不是 simpleView,@987654325 @感动。为避免这种情况,当用户触摸simpleView 时,我禁用了scrollView 的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 ;
      
      }
      

      【讨论】:

        【解决方案4】:

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

        UIScrollView subclass has changed behavior in iOS7

        【讨论】:

          猜你喜欢
          • 2012-08-10
          • 1970-01-01
          • 2023-03-06
          • 2012-03-17
          • 2011-07-11
          • 1970-01-01
          • 2023-03-29
          • 1970-01-01
          • 2015-01-19
          相关资源
          最近更新 更多