如何将手势识别器添加到一系列子视图中?

Posted

技术标签:

【中文标题】如何将手势识别器添加到一系列子视图中?【英文标题】:How can I add a Gesture Recognizer to a series of subviews? 【发布时间】:2012-04-21 12:57:46 【问题描述】:

我有一个显示在屏幕上的子视图图像网格;它基本上是以棋盘方式在屏幕上布置的一系列图像。我只是想为每个图像子视图添加手势识别器,以便当用户触摸其中一个图像子视图时,我可以检索子视图,即坐标、标签等。我的视图层次结构如下:

    超级视图 gridContainer 视图 以及每个单独的子视图 - 带有图像

查看苹果文档后,似乎我应该能够向 gridContainer 视图添加手势识别器,并且每个子视图(带有图像)都应该继承手势识别器。到目前为止,这是我尝试过的:我已经在 getter 中分配了初始化网格容器视图。此外,在 getter 中,我调用了我的 createGesture 方法,该方法应该将手势识别器添加到 gridContainer 视图。但是,我在运行时遇到错误,指向我的操作 handleSingleTap 方法。它读取 EXC_BAD_EXCESS。 还值得注意的是,我不希望我的 gridContainer 视图之外的视图响应任何触摸事件。提前感谢您的帮助。

这是我要实现的代码:

- (UIView *)gridContainerView

    if (!_gridContainerView)_gridContainerView = [[UIView alloc] init];
    [self createGesture];
    return _gridContainerView;

- (void)createGesture

    UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc]
                                         initWithTarget:self.gridContainerView
                                         action:@selector(handleSingleTap:)];
    singleTap.numberOfTapsRequired = 1;

    [self.gridContainerView addGestureRecognizer:singleTap];

如果您需要查看任何其他代码以使其有意义,请告诉我。

编辑:包括handleSingleTap方法:

- (IBAction)handleSingleTap:(id)sender

    CGPoint tapPoint = [sender locationInView:sender];
    NSLog(@"sender = %@",sender);
    NSLog(@"tappoint = %@", tapPoint);

【问题讨论】:

【参考方案1】:

您正在为您的 gridContainerView 初始化一个普通的UIView。然后将手势识别器附加到它(使用该视图实例作为目标)。一个普通的UIView 但是没有实现handleSingleTap:,因此你会得到一个异常。

您应该创建一个(自定义UIView 派生的)类来实现您需要触发该手势的选择器。

【讨论】:

所以我应该创建一个自定义类,它是 UIView 的子视图?我是否应该将我的 gridContainerView 推送到这个自定义类中,然后在我需要访问它时在我的控制器中调用它? 不是子视图,而是子类。【参考方案2】:

一开始就出现了几个问题(甚至没有处理你的手势)。

您将在每次访问 gridContainerView 时调用 createGesture。您可能只希望在创建视图时发生这种情况。另外,如果你看createGesture,它回调到gridContainerView,它回调到createGesture,它回调到gridContainerView等等。

你可能想要更像...的东西

- (UIView *)gridContainerView

    if (!_gridContainerView) 
        _gridContainerView = [[UIView alloc] init];
        [self createGesture];
    
    return _gridContainerView;

接下来,您尝试在视图上调用 handleSingleTap。您可能希望它在控制器上:initWithTarget:self。

- (void)createGesture

    UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc]
                                         initWithTarget:self
                                         action:@selector(handleSingleTap:)];
    singleTap.numberOfTapsRequired = 1;

    [self.gridContainerView addGestureRecognizer:singleTap];

您可能想重新利用两个独立的方法直接相互引用这样的智慧。但是,至少我们对访问器所做的更改应该没问题。只要知道,如果您在访问器中添加更多代码,则必须在调用 createGesture 之前完全设置视图。

【讨论】:

这些是一些优点,但是我的 handleSingleTap 方法似乎没有响应触摸事件。我在上面编辑了我的代码,并包含了句柄单击方法。知道为什么它没有响应吗?【参考方案3】:

几件事。首先,您将 gridContainerView 实例化为标准 UIView,然后向其发送消息:handleSingleTap:,它肯定不会响应。如果您希望您的 gridContainerView 响应消息,您需要子类化 UIView,创建适当的方法,并将您的 gridContainerView 实例化为子类。

其次,就整体方法而言,我将为 gridContainerView 创建子类(甚至可以这样称呼它)并创建处理手势的方法。在该方法中,您可以使用 UIGestureRecognizer 方法locationInView: 访问被触摸/点击的点。使用这一点来确定 gridContainerView 中的哪个子视图被点击并执行相应的操作。要发现哪个子视图被点击,您可以遍历您的子视图并检查每个子视图以确定哪个包含被点击的点。 UIView 有几种方法可以用来执行此操作:

pointInside:withEvent: hitTest:withEvent:

注意,您可以通过nil 参加活动。以上两件事做的事情略有不同。如果您只是测试该点是否位于视图中,请使用pointInside:withEvent,因为它将返回BOOLhitTest:withEvent 方法将导致视图搜索其所有子视图并返回其自身或其子视图之一(如果该点超出其边界,则返回 nil)。 hitTest:withEvent 可能会占用更多处理器资源。此外,您也可以使用CGRectContainsPoint() 进行测试。

【讨论】:

以上是关于如何将手势识别器添加到一系列子视图中?的主要内容,如果未能解决你的问题,请参考以下文章

识别视图中的滑动手势而不是子视图

UIScrollview 子视图在缩放后无法识别平移手势

如何将手势识别器从一个视图传递到另一个视图

当滚动视图子视图不在屏幕上时,手势识别器不起作用

在使用手势识别器添加子视图时遇到 UI 故障问题

将向上滑动手势识别器添加到模态视图