UIControl 未接收触摸

发布于 2025-01-07 01:00:30 字数 2495 浏览 0 评论 0原文

我有一个 UIControl,它实现了 Touchs Begin 方法,如下所示:

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

UIControl 的这个子类在视图控制器中实例化,然后将其作为子视图添加到该视图控制器中。我在 UIControl 的 Touchs Begin 方法处有一个断点,并且该方法永远不会被调用。我一直在阅读一些内容,似乎视图控制器有一些逻辑来决定是否将触摸事件传递给其子视图。奇怪的是,我在同一个视图控制器中有一个不同的 UIControl 子类,当用户触摸它时,触摸事件会传递给它! 代码:

.h.m

#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

这是完整的

#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

I have a UIControl which implements the touches began method like so:

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

This subclass of UIControl is instantiated in a view controller, it is then added as a subview to that view controller. I have a breakpoint at the touches began method of the UIControl, and the method never gets called. I've been doing some reading and it seems that the View Controller has some logic that decides whether to pass on touch events to its subviews. The strange thing is that I have a different subclass of UIControl in the same view controller, and the touch events get passed down to it when the user touches it!
Here is the full code:

.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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

内心荒芜 2025-01-14 01:00:30

tl;dr 将 UIControl 的所有子视图设置为 setUserInteractionEnabled:NO。 UIImageViews 默认将其设置为 NO

原始帖子

我最近发现的一件事是,如果 UIControl 的最顶层子视图有 setUserInteractionEnabled:NO ,它会有所帮助。我之所以这样做是因为我有一个带有 UIImageView 的 UIControl 子类,因为它只是子视图并且工作正常。默认情况下,UIImageView 将 userInteractionEnabled 设置为 NO

我还有另一个带有 UIView 的 UIControl,因为它是最顶层的子视图(技术上是处于不同状态的相同 UIControl)。我相信 UIView 默认为 userInteractionEnabled == YES,这排除了 UIControl 处理的事件。将 UIView 的 userInteractionEnabled 设置为 NO 解决了我的问题。

我不知道这里是否有同样的问题,但这也许会有帮助?

--
编辑:当我说最顶层视图时...可能将 UIControl 的所有子视图设置为 setUserInteractionEnabled:NO

tl;dr Set all subviews of the UIControl to setUserInteractionEnabled:NO. UIImageViews have it set to NO by default.

Original Post

One thing I found recently is that it helps if the top-most subview of the UIControl has setUserInteractionEnabled:NO. I arrived at this because I had a UIControl subclass with a UIImageView as it's only subview and it worked fine. UIImageView has userInteractionEnabled set to NO by default.

I also had another UIControl with a UIView as it's top most subview (technically the same UIControl in a different state). I believe UIView defaults to userInteractionEnabled == YES, which precluded the events being handled by the UIControl. Settings the UIView's userInteractionEnabled to NO solved my issue.

I don't know if it's the same issue here, but maybe that will help?

--
Edit: When I say topmost view... probably set all subviews of the UIControl to setUserInteractionEnabled:NO

风筝在阴天搁浅。 2025-01-14 01:00:30

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

Check frames of all parent views. The rule is that if sub-view (or its part) of the view is outside the view bounds, it doesn't receive touch events.

永不分离 2025-01-14 01:00:30

Xcode 12 及后者。

  • 正如接受的答案中提到的,确保
    UIControl 视图未选中“用户交互已启用”。
  • 选择您的
    UIControl视图并切换到“Connection Inspector”并进行
    确保它已连接到“Touch Up Inside”事件。有时
    Xcode 使用“Value Changed”事件,因此请确保更改为“Touch
    上内”活动

Xcode 12 and Latter.

  • As mention in the accepted answer, make sure all the subviews of the
    UIControl view get "User Interaction Enabled" unchecked.
  • Select your
    UIControl view and switch to the "Connection Inspector" and make
    sure it has been connected to "Touch Up Inside" event. Sometimes
    Xcode uses "Value Changed" event so make sure to change to "Touch
    Up Inside" event
阪姬 2025-01-14 01:00:30

另一个视图可能覆盖了您的 UIControl,并阻止它接收触摸事件。另一种可能性是 userInteractionEnabled 在某处被错误地设置为 NO

编辑:我看到您在上面添加了更多代码。您是否确认视图框架的宽度和高度大于零?在我看来,您是直接在 NSArray 中的对象(即“id”)上调用“size”。我不知道你是如何在没有强制转换的情况下做到这一点的(也许上面的括号没有出现?),但如果你以某种方式完成它,如果它是一个无效值,我不会感到惊讶。

It is possible that another view is covering your UIControl, and preventing it from receiving the touch events. Another possibility is that userInteractionEnabled is set to NO somewhere by mistake.

EDIT: I see that you added more code above. Did you verify that your view's frame has a width and height greater than zero? It looks to me like you are calling "size" directly on an object from NSArray (which is 'id'). I don't know how you are doing this without a cast (perhaps the parenthesis didn't come through above?) but if you are somehow pulling it off I wouldn't be surprised if it was an invalid value.

天生の放荡 2025-01-14 01:00:30

首先,为什么要调用[super TouchesBegan:touches withEvent:event];?此调用将事件转发给下一个响应者。通常只有当您不想处理该事件时才执行此操作。你确定你知道你在那里做什么吗?

为什么它不起作用 - 你是否有一个首先处理事件的手势识别器?

不管怎样,你真的需要重写 touchesBegan 吗? UIControl 用于自行跟踪触摸事件并调用处理程序作为响应。 UIControl 文档说明了如何对其进行子类化。

子类化注释

您可能出于以下两个原因想要扩展 UIControl 子类:

  • 观察或修改针对特定事件向目标发送操作消息的情况

    为此,请重写 sendAction:to:forEvent:,评估传入的选择器、目标对象或 UIControlEvents 位掩码,然后根据需要继续。

  • 提供自定义跟踪行为(例如,更改突出显示外观)

    为此,请重写以下方法之一或全部:beginTrackingWithTouch:withEvent:、 continueTrackingWithTouch:withEvent:、endTrackingWithTouch:withEvent:。

First, why do you call [super touchesBegan:touches withEvent:event];? This call is forwarding the event to the next responder. Usually you do it only when you don't want to handle the event. Are you sure you know what are you doing there?

An idea why it doesn't work - can it be that you have a gesture recognizer which handles the event first?

Anyway, do you really need to override touchesBegan? UIControl is made to track the touch events by itself and call your handlers in response. And the UIControl docs say HOW to subclass it.

Subclassing Notes

You may want to extend a UIControl subclass for either of two reasons:

  • To observe or modify the dispatch of action messages to targets for particular events

    To do this, override sendAction:to:forEvent:, evaluate the passed-in selector, target object, or UIControlEvents bit mask, and proceed as required.

  • To provide custom tracking behavior (for example, to change the highlight appearance)

    To do this, override one or all of the following methods: beginTrackingWithTouch:withEvent:, continueTrackingWithTouch:withEvent:, endTrackingWithTouch:withEvent:.

北恋 2025-01-14 01:00:30

可能性:

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

Possibilities:

  • You might have forgot to set the delegate for the UIControl.
  • The other UIControl which receives the touch is obscuring/covering over the UIControl.
迷迭香的记忆 2025-01-14 01:00:30

很公平。最近重新调查了这一点(UIControl 的记录非常少)并意识到跟踪触摸是对 TouchBegan/Ended 的替代,而不是附加,对此感到抱歉。我想推翻投票,但它不允许我:(

Fair enough. Recently re-investigated this (UIControl is very poorly documented) and realised that tracking touches is a replacement for touchesBegan/Ended, not an additional, so sorry about that. I'd reverse the vote but it wouldn't let me :(

落花随流水 2025-01-14 01:00:30

您可能需要在 UIControl 子类中重写 intrinsicContentSize

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

我不太明白它是如何解决的或为什么,但它有效。它甚至不需要是您控制的精确尺寸。

You might need to override intrinsicContentSize inside your UIControl subclass.

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

I don't quite understand how it fixes it or why, but it works. It doesn't even need to be the exact size as your control.

度的依靠╰つ 2025-01-14 01:00:30

UIView 实例无法响应事件,因此根据您当前的配置,无法触发您的操作方法?

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

UIView instances are unable to respond to events so there is no way, up to your current configuration, to trigger your action method ?

Try to change the class of the view to be an instance of the UIControl class !

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文