- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch* touch = [touches anyObject];
NSUInteger numTaps = [touch tapCount];
if (numTaps < 2) {
[self.nextResponder touchesBegan:touches withEvent:event];
} else {
[self handleDoubleTap:touch];
}
}
我有一个View Controller。如您所知,View Controllers继承自UIResponder。 View Controller创建一个继承自UIView的MyView对象,并将其作为子视图添加到它自己的视图中。
所以我们有:
查看控制器&gt;有一个视图(自动)&gt;有一个MyView(这是一个UIView)。
现在在MyView中,我把上面的代码放在一个打印“触摸MyView”的NSLog上。但我将事件转发给下一个响应者,就像上面一样。在ViewController中,我有另一个touchesBegan方法,只打印一个NSLog和一个“触摸视图控制器”。
现在猜猜:当我触摸MyView时,它会打印“触摸MyView”。当我触摸MyView的外部时,这是VC的视图,然后我得到一个“触摸的视图控制器”。所以两者都有效!但是什么不起作用是转发事件。因为现在,实际上下一个响应者应该是视图控制器,因为中间没有别的东西。但是当我转发它时,VC的事件处理方法永远不会被调用。
%$&安培;!§!!
想法?
想出奇怪的东西 MyView的下一个响应者是视图控制器的视图。这是有道理的,因为MyView是一个子视图。但是我没有从视图控制器修改这个UIView。这没什么习惯的。它没有实现任何触摸事件处理。消息是否应该传递给视图控制器?我怎么能让它通过?如果我在MyView中删除事件处理代码,那么事件很好地到达视图控制器。
答案 0 :(得分:5)
根据similar question,您的方法应该有效。
这让我认为您的观点nextResponder
实际上不是<{1}},正如您所怀疑的那样。
我会在您的转发代码中添加一个快速ViewController
,以检查您的NSLog
真正指向的内容:
nextResponder
您还可以更改其他NSLog消息,以便输出类型和地址信息:
if (numTaps < 2) {
NSLog(@"nextResponder = %@", self.nextResponder);
[self.nextResponder touchesBegan:touches withEvent:event];
}
NSLog(@"touched %@", self);
这可以帮助您开始诊断问题。
答案 1 :(得分:4)
这有问题,因为我的自定义视图在视图层次结构中更深。相反,我爬上了响应链,直到找到UIViewController
;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
// Pass to top of chain
UIResponder *responder = self;
while (responder.nextResponder != nil){
responder = responder.nextResponder;
if ([responder isKindOfClass:[UIViewController class]]) {
// Got ViewController
break;
}
}
[responder touchesBegan:touches withEvent:event];
}
答案 2 :(得分:2)
是的,它应该100%在常见情况下工作。我刚试过测试项目,一切似乎都没问题。
我创建了基于视图的应用程序。使用Interface Builder将新的UIView放到当前View中。然后使用UIView的子类创建新文件,并为我的新视图选择刚创建的类。 (Interface Builder-&gt; Class identity-&gt; Class-&gt; MyViewClass)
为MyViewClass和UIViewController添加touches处理函数。
// MyViewClass
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(@"myview touches");
[self.nextResponder touchesBegan:touches withEvent:event];
}
// ViewController
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(@"controller touches");
}
按下MyViewClass时,我看到两个NSLog。在加载ViewController或使用loadView函数以编程方式设置视图时,是否使用了Interface Builder和XIB文件?
答案 3 :(得分:2)
要引用视图控制器,您需要使用
[[self nextResponder] nextResponder]
因为[self nextResponder]
表示视图控制器的视图,
和[[self nextResponder] nextResponder]
表示视图控制器本身,现在您可以获得触摸事件
答案 4 :(得分:2)
如果查看UIResponder
的文档,默认情况下说明会说明:
UIView通过返回管理它的UIViewController对象(如果有的话)或超级视图(如果没有)来实现此方法;
如果您的视图没有返回视图控制器,那么它必须返回其超级视图(如您所知)。
UIApplication实际上有一个方法应该完全处理这个用例:
- (BOOL)sendAction:(SEL)action
to:(id)target
from:(id)sender
forEvent:(UIEvent *)event
由于您没有对目标的引用,因此根据文档,您可以通过将目标值设置为nil
来逐步提升响应者链:
如果target为nil,应用程序会将消息发送给第一个响应者,从而从响应者链向上进行处理。
您当然可以使用类方法[UIApplication sharedApplication]
此处有更多信息:UIApplication documents
这是额外的,但是如果你绝对需要访问视图控制器来做一些更复杂的事情,你可以手动向上操作响应链,直到你通过调用nextResponder
方法到达视图控制器。它返回一个视图控制器。例如:
UIResponder *responder = self;
while ([responder isKindOfClass:[UIView class]])
responder = [responder nextResponder];
然后你可以把它作为你的视图控制器投射,并继续做你想做的事情:
UIViewController *parentVC = (UIViewController *)responder
答案 5 :(得分:1)
我知道这篇文章很老但我觉得id分享,因为我有类似的经历。我通过为自动创建的视图控制器的视图将userInteractionEnabled设置为NO来修复它。
答案 6 :(得分:1)
今天我找到了一个更好的方法来解决这个或类似的问题。
在您的UITableViewCell中,您可以添加一个委托来监听触摸事件,如下所示:
@protocol imageViewTouchDelegate
-(void)selectedFacialView:(NSInteger)row item:(NSInteger)rowIndex;
@end
@property(nonatomic,assign)id<imageViewTouchDelegate>delegate;
然后在你的UITableViewController中:你可以这样做:
@interface pressionTable : UITableViewController<facialViewDelegate>
在.m文件中,您可以实现此委托接口,例如:
-(void)selectedFacialView:(NSInteger)row item:(NSInteger)rowIndex{
//TO DO WHAT YOU WANT}
注意:当你初始化单元格时,你必须设置委托,否则委托是无效的,你可以这样做
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
pressionCell *cell = (pressionCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[pressionCell alloc]initWithFrame:CGRectMake(0, 0, 240, 40)];
}
cell.delegate = self;
}
PS:我知道这个DOC已经老了,但是我仍然添加我的方法来修复问题,所以当人们遇到同样的问题时,他们会从我的答案中得到帮助。答案 7 :(得分:1)
使用此
[super.nextResponder touchesBegan:touches withEvent:event];
在代码中此行之前
[self.nextResponder touchesBegan:touches withEvent:event];
它的意思是
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch* touch = [touches anyObject];
NSUInteger numTaps = [touch tapCount];
if (numTaps < 2) {
[super.nextResponder touchesBegan:touches withEvent:event];
[self.nextResponder touchesBegan:touches withEvent:event];
} else {
[self handleDoubleTap:touch];
}
}
** Swift 4版本**
func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
let touch = touches?.first as? UITouch
let numTaps: Int? = touch?.tapCount
if (numTaps ?? 0) < 2 {
if let aTouches = touches as? Set<UITouch> {
super.next?.touchesBegan(aTouches, with: event)
next?.touchesBegan(aTouches, with: event)
}
} else {
handleDoubleTap(touch)
}
}