UIControl 未接收触摸
我有一个 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
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 toNO
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 hasuserInteractionEnabled
set toNO
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'suserInteractionEnabled
toNO
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
检查所有父视图的
frame
。规则是,如果视图的子视图(或其部分)位于视图边界之外,则它不会接收触摸事件。Check
frame
s 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.Xcode 12 及后者。
UIControl 视图未选中“用户交互已启用”。
UIControl视图并切换到“Connection Inspector”并进行
确保它已连接到“Touch Up Inside”事件。有时
Xcode 使用“Value Changed”事件,因此请确保更改为“Touch
上内”活动
Xcode 12 and Latter.
UIControl view get "User Interaction Enabled" unchecked.
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
另一个视图可能覆盖了您的 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 toNO
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.
首先,为什么要调用
[super TouchesBegan:touches withEvent:event];
?此调用将事件转发给下一个响应者。通常只有当您不想处理该事件时才执行此操作。你确定你知道你在那里做什么吗?为什么它不起作用 - 你是否有一个首先处理事件的手势识别器?
不管怎样,你真的需要重写
touchesBegan
吗?UIControl
用于自行跟踪触摸事件并调用处理程序作为响应。UIControl
文档说明了如何对其进行子类化。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 theUIControl
docs say HOW to subclass it.可能性:
Possibilities:
很公平。最近重新调查了这一点(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 :(
您可能需要在
UIControl
子类中重写intrinsicContentSize
。我不太明白它是如何解决的或为什么,但它有效。它甚至不需要是您控制的精确尺寸。
You might need to override
intrinsicContentSize
inside yourUIControl
subclass.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.
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 !