Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/42.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone hitTest返回错误的UIView_Iphone_Ipad_Ios_Hittest - Fatal编程技术网

Iphone hitTest返回错误的UIView

Iphone hitTest返回错误的UIView,iphone,ipad,ios,hittest,Iphone,Ipad,Ios,Hittest,我有一个视图层次结构,在滚动视图中包含较小的视图。每个视图中都可以有子视图,如按钮等 由于某些原因,视图上的按钮没有被单击;进一步探究这一点可以发现,当滚动视图接收到touchStart事件时,按钮不会。调用hitTest:event:message显示按钮未返回,即使它在限制范围内 我已经包括了一个日志输出,描述了触摸屏在滚动视图上的位置、从hitTest返回的项目、触摸屏的位置(如果我调用locationInView:使用预期项目)以及预期项目的层次结构(打印了框架)。从这个输出,我可以推断

我有一个视图层次结构,在滚动视图中包含较小的视图。每个视图中都可以有子视图,如按钮等

由于某些原因,视图上的按钮没有被单击;进一步探究这一点可以发现,当滚动视图接收到touchStart事件时,按钮不会。调用hitTest:event:message显示按钮未返回,即使它在限制范围内

我已经包括了一个日志输出,描述了触摸屏在滚动视图上的位置、从hitTest返回的项目、触摸屏的位置(如果我调用locationInView:使用预期项目)以及预期项目的层次结构(打印了框架)。从这个输出,我可以推断按钮应该被调用

有人能解释一下吗?我错过什么了吗

touched ({451, 309}) on <VCViewContainersView: 0x4b31ee0; frame = (0 0; 748 1024); transform = [0, 1, -1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0x4b32130>> (location in expected item: {17, 7.5})
expected touched item is:
view: <UIButtonLabel: 0x482b920; frame = (32 5; 36 19); text = 'Click'; clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x4831370>>, layer transform: [1, 0, 0, 1, 0, 0]
 view: <UIRoundedRectButton: 0x482c100; frame = (50 50; 100 30); opaque = NO; layer = <CALayer: 0x482c450>>, layer transform: [1, 0, 0, 1, 0, 0]
  view: <UIImageView: 0x480f290; frame = (0 0; 320 255); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x480e840>>, layer transform: [1, 0, 0, 1, 0, 0]
   view: <VCViewContainer: 0x4b333c0; frame = (352 246.5; 320 471.75); layer = <CALayer: 0x4b33d50>>, layer transform: [1, 0, 0, 1, 0, 0]
    view: <UIScrollView: 0x4b32600; frame = (0 0; 1024 748); clipsToBounds = YES; autoresize = W+H; userInteractionEnabled = NO; layer = <CALayer: 0x4b32780>>, layer transform: [1, 0, 0, 1, 0, 0]
     view: <VCViewsContainerView: 0x4b31ee0; frame = (0 0; 748 1024); transform = [0, 1, -1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0x4b32130>>, layer transform: [0, 1, -1, 0, 0, 0]
      view: <UIWindow: 0x4b1d590; frame = (0 0; 768 1024); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x4b1d6d0>>, layer transform: [1, 0, 0, 1, 0, 0]
触摸({451309})在(预期项目中的位置:{17,7.5})
预期项目为:
视图:,层变换:[1,0,0,1,0,0]
视图:,层变换:[1,0,0,1,0,0]
视图:,层变换:[1,0,0,1,0,0]
视图:,层变换:[1,0,0,1,0,0]
视图:,层变换:[1,0,0,1,0,0]
视图:,层变换:[0,1,-1,0,0,0]
视图:,层变换:[1,0,0,1,0,0]
更新:除了UIWindow和VCViewsContainerView之外,所有视图都是使用initWithFrame:或按钮类型的按钮以编程方式创建的。VCViewContainer使用CGRectZero初始化,创建UIImageView时,其框架设置为图像大小+底部标签的额外空间


更新2:当使用相同的位置调用[self.layer hitTest:location]时,我得到了正确视图的层!这里发生了什么…?

如果我正确理解视图堆栈,则您的按钮是某个UIImageView的子视图-它的
userInteractionEnabled
属性设置为“否”(默认情况下)-因此图像视图及其所有子视图不会接收任何触摸事件


将图像视图的
userInteractionEnabled
属性设置为
YES
必须解决此问题

hitTest:withEvent:从窗口开始。每个视图在测试自身之前测试其子视图,以此类推。但是,如果视图的userInteractionEnabled为否,则它会从hitTest:withEvent:返回nil,而不测试其子视图。这样的视图当然是经过命中测试的,但它立即回答说,它和它的任何子视图都不是命中视图

您可以将UIScrollView的userInteractionEnabled设置为NO。因此,当VCViewContainerView测试其子视图UIScrollView时,UIScrollView返回nil,因为其userInteractionEnabled为NO,VCViewContainerView在其自身上使用pointInside:withEvent:时,会发现触摸在其内部,并将其自身作为点击视图返回(搜索结束)。这解释了您得到的结果

通过层进行命中测试时不会发生这种情况的原因是层是不可触摸的,并且对触摸规则一无所知,因此它们忽略了userInteractionEnabled,这是一种视图功能,而不是层功能。层命中测试是一种混球,仅适用于视图包含整个层层次结构的情况(没有视图层次结构)并且您希望模拟某个特定的层是可触摸的。文档确实告诉您,层的hitTest:的逻辑与视图的hitTest:withEvent:的逻辑不同,尽管它们无法准确解释如何操作


我不知道为什么您将滚动视图设置为不可触摸,但如果这对您很重要,您可以在UIScrollView子类中覆盖hitTest:withEvent:以便它测试其子视图,但如果所有子视图都返回nil,则返回nil。

您可能希望尝试将UIScrollView子类化,以接收对其中对象的触摸

默认情况下,您的触摸将由UIScrollView接收,因此,如果您希望在其中的对象上接收触摸,则需要显式设置

这里有一个正在工作的子类来实现这一点。感谢SO社区的支持,因为我相信我最初在这里找到了类似的东西,只是现在无法挖掘原始帖子

以下是.h:

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface TouchScroller : UIScrollView 
{
}

@end

应该可以了。

UIRoundedRectButton就是这个按钮。我们需要看看你是如何创建视图层次结构的……界面生成器、代码等等。@KennyTM:如果不清楚,它会说“在(实际接触的项目)上触摸(位置)”。请注意,被触动的项目是VCViewContainerView,而不是UIRoundedRectButton。@jv42:我已经添加了解释;添加代码是一件很遗憾的事情,因为它散落在各处。如果您仍然需要代码,我会修改一些内容。以防万一我尝试了,但不幸的是,事实并非如此。我认为您所说的不是真的;文档指定对事件处理程序的搜索是自上而下的,因此应该首先测试按钮。在任何情况下,hitTest:根本不受用户交互的影响。+1感谢解释
hitTest:withEvent:
userInteractionEnabled
NO
@AlexanderFarber for m时返回
nil
y触摸交付和命中测试的完全逆向工程,请参见:谢谢你,Matt,我在Safari上读了你的书-这本书非常有用。你对我目前的问题(bounty 500)有什么建议吗?我无法找到正确的
hitTest:withEvent:
方法。我想你在这方面得到了很多帮助!
#import "TouchScroller.h"


@implementation TouchScroller

- (id)initWithFrame:(CGRect)frame 
{
return [super initWithFrame:frame];
}

- (void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event 
{   
// If not dragging, send event to next responder
if (!self.dragging) 
    [self.nextResponder touchesEnded: touches withEvent:event]; 
else
    [super touchesEnded: touches withEvent: event];
}

@end