UIControl无法接收触摸信号

30

我有一个实现了touches began方法的UIControl:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];
    //More code goes here

这个UIControl的子类被实例化于一个视图控制器中,然后作为该视图控制器的子视图添加进去。我在UIControl的touches began方法下打了一个断点,但是这个方法从未被调用过。我阅读了一些资料,发现视图控制器有一些逻辑来决定是否将触摸事件传递给它的子视图。奇怪的是,在同一个视图控制器中,我有另一个UIControl的子类,当用户触碰它时,触摸事件会被传递给它!以下是完整的代码:

.h

#import <UIKit/UIKit.h>

@interface CustomSegment : UIView
@property (nonatomic, strong) UIImageView *bgImageView;
@property (nonatomic, assign) NSInteger segments;
@property (nonatomic, strong) NSArray *touchDownImages;
@property (nonatomic, readonly, assign) NSInteger selectedIndex;
@property (nonatomic, weak) id delegate;


- (id)initWithPoint:(CGPoint)point numberOfSegments:(NSInteger)_segments andTouchDownImages:(NSArray *)_touchDownImages;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
@end

.m

#import "CustomSegment.h"

@implementation CustomSegment
@synthesize bgImageView, segments, touchDownImages, selectedIndex, delegate;

- (id)initWithPoint:(CGPoint)point
   numberOfSegments:(NSInteger)_segments
           andTouchDownImages:(NSArray *)_touchDownImages  
{  
    self = [super initWithFrame:CGRectMake(point.x, point.y, [[_touchDownImages     objectAtIndex:0] size].width, [[touchDownImages objectAtIndex:0] size].height)];
if (self)
{
    touchDownImages = _touchDownImages;
    segments = _segments;
    bgImageView = [[UIImageView alloc] initWithImage:[touchDownImages objectAtIndex:0]];
    [self addSubview:bgImageView];
}
return self;
}

- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
    return YES;  
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    //[super touchesBegan:touches withEvent:event];
    UITouch *touch = [touches anyObject];
    float widthOfSegment = [self frame].size.width / segments;
    float bottomPoint = 0;
    float topPoint = widthOfSegment;
    for (int i = 0; i < segments; i++)
    {
        if ([touch locationInView:self].x > bottomPoint && [touch locationInView:self].x < topPoint)
        {
            [bgImageView setImage:[touchDownImages objectAtIndex:i]];
            selectedIndex = i;
            return;
        }
        else
        {
            bottomPoint = topPoint;
            topPoint += topPoint;
        }
    }
}
@end

你如何添加两个UIControl子视图?你能展示一些代码吗? - sch
解决方案在这里的一个重复线程中,由“jhabbot”提供 https://dev59.com/cXM_5IYBdhLWcg3wvV9w - Tom Susel
9个回答

120

简述:将UIControl的所有子视图都设置为setUserInteractionEnabled:NO,其中UIImageView默认情况下已设置为NO

原始帖子

我最近发现一个有用的技巧是如果UIControl的最上层子视图具有setUserInteractionEnabled:NO属性,则会有所帮助。我之所以这样做是因为我有一个UIControl子类,其唯一的子视图是UIImageView,并且它可以正常工作。UIImageView默认情况下将 userInteractionEnabled 设置为NO

我还有另一个UIControl,其顶部子视图为UIView(实际上是不同状态下的同一UIControl)。我相信UIView将userInteractionEnabled == YES作为默认值,这排除了UIControl处理事件的可能性。 将UIView的userInteractionEnabled设置为NO解决了我的问题。

我不知道这是否适用于此问题,但也许这能帮到你?

--修改:当我说顶部视图时... 可能需要将UIControl的所有子视图都设置为setUserInteractionEnabled:NO


8
已经过去三年了。Kyle 应该接受这个答案! - Klaas
1
啊,这让我疯狂了,然后我看到了你的答案,尝试在子视图之外轻敲一下,它就起作用了。谢谢! - Christopher Pickslay
1
应该被接受的答案,确保顶部视图没有用户交互即可修复。谢谢。 - crashoverride777
1
哎呀!我已经撞了几个小时的墙,试图理解为什么我的自定义UIControl没有接收到事件!非常感谢你! - Serzhas

3

Xcode 12及以上版本。

  • 如已接受的答案所述,请确保UIControl视图的所有子视图都未选中“用户交互启用”。
  • 选择您的UIControl视图并切换到“连接检查器”,确保已将其连接到“Touch Up Inside”事件。有时Xcode会使用“Value Changed”事件,因此请确保更改为“Touch Up Inside”事件。

3

检查所有父视图的frame。规则是,如果子视图(或其部分)在视图边界之外,则它不会接收触摸事件。


谢谢ivanzoid,视图控制器(UIControl的父级)的框架是整个屏幕,所以这不应该是一个问题。特别是因为UIControl非常小。不过还是谢谢。 - Kyle Rosenbluth

1

可能出现的情况是另一个视图覆盖在您的UIControl上,从而防止其接收触摸事件。另一种可能性是userInteractionEnabled 在某个地方被错误地设置为 NO

编辑:我看到你上面添加了更多代码。请验证您的视图框架的宽度和高度是否大于零?看起来你直接在NSArray的对象上调用“size”(它是'id')。我不知道你是如何做到这一点而没有进行转换(也许括号没有正确显示?)但是如果您以某种方式完成了它,那么如果它是无效值,我将不会感到惊讶。


没有任何东西覆盖它,而且userInteractionEnables在任何地方都没有设置为NO。感谢您的建议。 - Kyle Rosenbluth

1

首先,为什么要调用[super touchesBegan:touches withEvent:event];?这个调用是将事件转发给下一个响应者。通常只有在不想处理事件时才会这样做。你确定你知道自己在那里做什么吗?

为什么它不起作用的一个想法 - 可能是你有一个手势识别器先处理了事件吗?

无论如何,你真的需要重写touchesBegan吗?UIControl本身就可以跟踪触摸事件并调用你的处理程序来响应。而且UIControl文档中也说明了如何对其进行子类化。

子类化说明 你可能想要扩展一个UIControl的子类,有两个原因:
- 观察或修改特定事件的目标的操作消息的分发

为此,请重写sendAction:to:forEvent:方法,评估传入的选择器、目标对象或UIControlEvents位掩码,并根据需要进行处理。
- 提供自定义跟踪行为(例如,更改高亮外观)

为此,请重写以下一个或多个方法:beginTrackingWithTouch:withEvent:,continueTrackingWithTouch:withEvent:,endTrackingWithTouch:withEvent:。

1
谢谢Sulthan,我同意我不应该调用super。没有手势识别器,我尝试使用begintrackingtouch而不是仅使用touches began,但结果相同。我发现真正奇怪的是,我有一个不同的UIControl可以正常工作,并且我确保以完全相同的方式处理了触摸。然而,它仍然无法正常工作。 - Kyle Rosenbluth
另一个想法 - 它在 UIScrollView 中,该视图会取消其内容的触摸事件?有很多可能性。 - Sulthan
为了简化事情,我创建了一个空应用程序,其中只有一个空的vc,并且我放置在其中的唯一控件。仍然存在相同的问题。这非常令人沮丧,但感谢您的所有帮助。 - Kyle Rosenbluth
此时,我不妨编辑原帖,在上方添加代码。 - Kyle Rosenbluth
在UIControl的子类中,你应该始终调用触摸处理方法中的'Super',否则它的跟踪触摸方法将无法触发。 - Ash
@Ash 如果你在 touchesBegan 方法中处理操作,通常不需要调用 super。这就是为什么 UIControl 通常不会以这种方式被重写。如果你仔细阅读我的回答,你就会明白的。 - Sulthan

0
可能性:
  • 您可能忘记为UIControl设置委托。
  • 接收触摸的另一个UIControl遮挡/覆盖了该UIControl。

谢谢,我没想到 UIControl 需要一个委托。也许我没有表达清楚,但是 touches began 是在我的 UIControl 子类中的。我之前考虑过有什么东西盖住了它,但事实并非如此,还是谢谢。 - Kyle Rosenbluth

0

好的。最近重新调查了一下(UIControl文档非常差),发现跟踪触摸是替代touchesBegan/Ended的,而不是额外的,所以对此感到抱歉。我想撤销投票,但不允许我:(


0

你可能需要在你的UIControl子类中重写intrinsicContentSize方法。

override var intrinsicContentSize: CGSize {
    return CGSize(width: 150, height: 100)
}

我不太明白它是如何修复的,也不知道为什么,但它能正常工作。它甚至不需要与你的控件大小完全相同。


-2

UIView实例无法响应事件,因此在当前配置下,没有办法触发您的操作方法?

尝试将视图的类更改为UIControl类的实例!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接