我正在使用iphone(iOS 4.0或更高版本)应用,并且在多个视图之间遇到触摸处理问题。我有这样的视图结构
---> A superView
|
---> SubView - A
|
---> SubView - B (exactly on top of A, completely blocking A).
基本上我有一个superView和兄弟子视图A和B. B与A具有相同的框架,因此完全隐藏了A.
现在我的要求就是这个。
这是我为视图添加手势识别器的方式
UISwipeGestureRecognizer *leftSwipe = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(leftSwipe:)];
[leftSwipe setDirection:(UISwipeGestureRecognizerDirectionLeft)];
leftSwipe.delegate = self;
[bView addGestureRecognizer:leftSwipe];
[leftSwipe release];
UISwipeGestureRecognizer *rightSwipe = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(rightSwipe:)];
[rightSwipe setDirection:(UISwipeGestureRecognizerDirectionRight)];
rightSwipe.delegate = self;
[bView addGestureRecognizer:rightSwipe];
[rightSwipe release];
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(handlePinch:)];
pinch.delegate = self;
[aView addGestureRecognizer:pinch];
[pinch release];
我做了一些研究,对我来说UIGestureRecognizerDelegate
看起来很有希望,我实施了委托方法
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
我为SubView B返回NO,希望底层视图能够获得这些事件。虽然没有这样的运气
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
if ([gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]] && [gestureRecognizer view] == bView) {
NSLog(@"pinchGesture");
//bView.userInteractionEnabled = NO;
return NO;
}
return YES;
}
然后我在委托回调(上面的块中注释的代码)中禁用了SubView B的用户交互,当识别到捏合手势时,希望剩余部分的手势将被SubView A接收。也没有这样的运气..
这就是我现在的立场。我看到了this个问题,其中接受的答案涉及财产cancelsTouchesInView
。但我相信cancelsTouchesInView
只取消特定的触摸事件,不要转发它。
任何其他方式来达到我的要求?我准备好处理你提供的任何暗示。
我所谓的subView A实际上是第三方库的View类的一个实例,它接受了所有触摸,我对它上面的任何手势都没有任何控制权。我想要左右滑动的不同实现,我想要捏,点击等工作,就像它正在使用这个第三方视图。所以我在A(SubView B)的顶部放置了一个视图以获得左右滑动。但现在我想将其他手势事件转发到底层库。
答案 0 :(得分:18)
如果我没有正确解决您的问题,您可以添加另一个带有rect的清晰视图,与A和B视图相同,并在其上实现所有手势:当您执行捏合手势时,控制子视图A,当滑动并点按(单和双)手势 - 控制子视图B.你可以采用不同的方式:通过指针或只是将复活的手势发送到课堂上的方法,它控制你的子视图。
例如:
UISwipeGestureRecognizer *leftSwipe = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(leftSwipe:)];
[leftSwipe setDirection:(UISwipeGestureRecognizerDirectionLeft)];
leftSwipe.delegate = subViewAcontroller;
[clearView addGestureRecognizer:leftSwipe];
[leftSwipe release];
UISwipeGestureRecognizer *rightSwipe = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(rightSwipe:)];
[rightSwipe setDirection:(UISwipeGestureRecognizerDirectionRight)];
rightSwipe.delegate = subViewAcontroller;
[clearView addGestureRecognizer:rightSwipe];
[rightSwipe release];
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(handlePinch:)];
pinch.delegate = subViewBcontroller;
[clearView addGestureRecognizer:pinch];
[pinch release];
或:
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
if ([gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]]) {
NSLog(@"pinchGesture");
[subViewBcontroller solvePinchGesture: gestureRecognizer];
}
//etc
return YES;
}
答案 1 :(得分:15)
aView从未收到过捏合手势,因为您查看的层次结构不正确。
---> A superView
|
---> SubView - A
|
---> SubView - B (exactly on top of A, completely blocking A).
bView将捕获所有多点触摸,包括捏合手势,但bView将不会处理捏合手势,因此它会将其传递给Responder链中的Next响应者,即bView的superView或bView的viewController。 pinch事件永远不会传递给它的兄弟视图,因为它们是并行的(没有parent-child或view-viewController关系)。
您可以按如下方式更改视图层次结构:
---> A superView
|
---> SubView - A
|
---> SubView - B (child view of b, exactly on top of A, completely blocking A)
- (void)viewDidLoad {
[super viewDidLoad];
aView = [[UIView alloc] initWithFrame:self.view.bounds];
aView.backgroundColor = [UIColor blueColor];
bView = [[UIView alloc] initWithFrame:self.view.bounds];
bView.backgroundColor = [UIColor redColor];
[self.view addSubview:aView];
[aView addSubview:bView];
UISwipeGestureRecognizer *leftSwipe = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(leftSwipe:)];
[leftSwipe setDirection:(UISwipeGestureRecognizerDirectionLeft)];
leftSwipe.delegate = self;
[bView addGestureRecognizer:leftSwipe];
UISwipeGestureRecognizer *rightSwipe = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(rightSwipe:)];
[rightSwipe setDirection:(UISwipeGestureRecognizerDirectionRight)];
rightSwipe.delegate = self;
[bView addGestureRecognizer:rightSwipe];
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(handlePinch:)];
pinch.delegate = self;
[aView addGestureRecognizer:pinch];
}
- >在响应者链中传递事件的重要说明 “当系统发送触摸事件时,它首先将其发送到特定视图。对于触摸事件,该视图是hitTest返回的视图:withEvent:;用于”摇动“ - 运动事件,远程控制事件,动作消息,和编辑菜单消息,该视图是第一个响应者。如果初始视图不处理该事件,它沿着特定路径沿着响应者链向上移动:
我上面的回答并不是唯一的解决方案,您需要做的是在同一个响应程序链中进行滑动和捏合手势处理逻辑,因此未处理的捏合手势事件将传递给正确的响应者。例如,您可以省略子视图b,并将滑动左/右手势添加到aView的superView。
答案 2 :(得分:1)
我前段时间做过类似的事情。我想用一根手指和两根或多根手指做两件不同的事情。我的解决方案可能需要一些调整,我不能确保在代码环境中一切都会完全相同。我没有找到适当的hitTest文档以及连续多次调用它的原因。所以我做了一些测试并找到了解决方案,如何分离一个和多个手指的手势,这非常适合我的需求。
我有这个视图层次结构:
---> A superView
|
---> ScrollView - A - all touches
|
---> ScrollView - B - only two+ finger scroll (exactly on top of A, completely blocking A).
我在superView的hitTest中实现了开关:
BOOL endDrag; // indicates scrollviewB did finish
BOOL shouldClearHitTest; // bool to help calling the method clearHitTest only once.
BOOL multiTouch; // needed for the method clearHitTest to know if a multi-touch is detected or not
NSMutableArray *events; // store all events within one eventloop/touch;
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if (!endDrag) {
if (!shouldClearHitTest) { // as hitTest will be called multible times in one event-loop and i need all events, i will clean the temporaries when everything is done
shouldClearHitTest = YES;
[[NSRunLoop mainRunLoop] performSelector:@selector(clearHitTest) target:self argument:nil order:1 modes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
}
[events addObject:event]; // store the events so i can access them after all hittests for one touch are evaluated
if (event.type == UIEventTypeTouches && ([_events count] > 3 || [[event allTouches] count] > 0 || _currentEvent)) { // two or more fingers detected. at least for my view hierarchy
multiTouch = YES;
return scrollViewB;
}
}else {
endDrag = NO;
}
return scrollViewA;
}
- (void)clearHitTest {
if (shouldClearHitTest) {
shouldClearHitTest = NO;
[events removeAllObjects];
if (multiTouch) {
// Do some special stuff for multiTouch
}
multiTouch = NO;
}
}
答案 3 :(得分:0)
我建议您在需要的地方使用以下代码可以帮助您。
//--->for bview gesture to detect swipe
[pinch requireGestureRecognizerToFail:leftSwipe]; &&
[pinch requireGestureRecognizerToFail:rightSwipe];
//--->for aview gesture to detect pinch
[rightSwipe requireGestureRecognizerToFail:rightSwipe]; ||
[leftSwipe requireGestureRecognizerToFail:pinch];
答案 4 :(得分:0)
如果bView有捏手势。从bView的捏手势动作,如果调用aView的捏手势动作,那么......
UIPinchGestureRecognizer *pinchA = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(handlePinchA:)];
[aView addGestureRecognizer:pinchA];
[pinchA release];
UIPinchGestureRecognizer *pinchB = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(handlePinchB:)];
[bView addGestureRecognizer:pinchB];
[pinchB release];
-(void)handlePinchA:(UIGestureRecognizer*)gestureRecognizer
{
NSLog(@"handlePinch on A");
}
-(void)handlePinchB:(UIGestureRecognizer*)gestureRecognizer
{
NSLog(@"handlePinch on B");
[self handlePinchA:gestureRecognizer];
}
aView是第三个副本。你能从外面打电话给 handlePinchA 吗? NSLog gestureRecognizers 打印出我 action = handlePinchA
NSLog(@"gestureRecognizers %@", [aView gestureRecognizers]);
打印我:
gestureRecognizers (
"<UIPinchGestureRecognizer: 0x8b3e500; state = Possible; view = <UIView 0x8b2f470>; target= <(action=handlePinchA:, target=....