UIGesture를 뒤에있는 뷰로 전달
iPhone (iOS 4.0 이상) 앱에서 작업 중이며 여러보기 간의 터치 처리에 문제가 있습니다. 나는 이와 같은 뷰 구조를 가지고 있습니다.
---> A superView
|
---> SubView - A
|
---> SubView - B (exactly on top of A, completely blocking A).
기본적으로 superView가 있고 형제 하위 뷰 A와 B가 있습니다. B는 A와 프레임이 동일하므로 A를 완전히 숨 깁니다.
이제 내 요구 사항은 이것입니다.
- SubView B는 모든 스 와이프 및 탭 (싱글 및 더블) 제스처를 수신해야합니다.
- SubView 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에서 수신되기를 바라고 있습니다. 그런 행운도 없습니다.
그래서 내가 지금 서있는 곳입니다. 나는 이 질문 을 보았는데 , 여기에서 받아 들여지는 대답은 재산과 관련이 있습니다 cancelsTouchesInView
. 하지만 cancelsTouchesInView
특정 터치 이벤트 만 취소하고 전달하지 않습니다.
내 요구 사항을 달성하는 다른 방법이 있습니까? 나는 당신이 제공하는 힌트에 대해 일할 준비가되어 있습니다.
편집 : 현상금 시간
내 소위 subView A는 실제로 타사 라이브러리의 View 클래스의 인스턴스로, 모든 터치를 없애고 제스처를 제어 할 수 없습니다. 왼쪽 및 오른쪽 스 와이프에 대해 다른 구현을 원하고이 타사보기에서 작업하는 것처럼 핀치, 탭 등이 작동하기를 원합니다. 그래서 왼쪽과 오른쪽으로 스 와이프하기 위해 A (SubView B) 위에 뷰를 배치했습니다. 하지만 이제는 다른 제스처 이벤트를 기본 라이브러리로 전달하고 싶습니다.
문제가 올바른지 이해하지 못하는 경우 A 및 B보기와 동일한 rect로 다른 명확한보기를 추가하고 모든 제스처를 구현할 수 있습니다. double) 제스처-subView 제어 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;
}
보기 계층 구조가 올바르지 않기 때문에 핀치 제스처는 aView에 의해 수신되지 않습니다.
---> A superView
|
---> SubView - A
|
---> SubView - B (exactly on top of A, completely blocking A).
bView는 핀치 제스처를 포함한 모든 멀티 터치를 캡처하지만 bView는 핀치 제스처를 처리하지 않으므로 응답자 체인의 다음 응답자, 즉 bView의 superView 또는 bView의 viewController에 전달합니다. pinch 이벤트는 병렬 (부모-자식 또는 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];
}
아래 링크에서 자세한 정보를 얻으십시오 : https://developer.apple.com/library/ios/#documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/EventsiPhoneOS/EventsiPhoneOS.html#//apple_ref/doc/uid/TP40009541-CH2-SW1
-> 응답자 체인에서 전달되는 이벤트에 대한 중요 참고 사항 "시스템이 터치 이벤트를 전달하면 먼저 특정 뷰로 보냅니다. 터치 이벤트의 경우 해당 뷰는 hitTest : withEvent :에 의해 반환 된 뷰입니다. ”-움직임 이벤트, 원격 제어 이벤트, 작업 메시지 및 편집 메뉴 메시지는 해당보기가 첫 번째 응답자입니다. 초기보기가 이벤트를 처리하지 않으면 특정 경로를 따라 응답자 체인 위로 이동합니다.
- 적중 테스트보기 또는 첫 번째 응답자는보기 컨트롤러가있는 경우 이벤트 또는 메시지를 해당보기 컨트롤러에 전달합니다. 뷰에 뷰 컨트롤러가 없으면 이벤트 또는 메시지를 수퍼 뷰에 전달합니다.
- 뷰 또는 뷰 컨트롤러가 이벤트 또는 메시지를 처리 할 수없는 경우 뷰의 수퍼 뷰로 전달합니다.
- Each subsequent superview in the hierarchy follows the pattern described in the first two steps if it cannot handle the event or message.
- The topmost view in the view hierarchy, if it doesn’t handle the event or message, passes it to the window object for handling.
- The UIWindow object, if it doesn’t handle the event or message, passes it to the singleton application object."
my answer above is not the only solution, what you need to do is make swipe and pinch gesture handling logics in the same responder chain, so the un-handle pinch gesture event will passed to the correct responder. For example, you can omit subview b, and add the swipe left/right gestures to superView of aView.
I did something similar some time ago. I wanted to do two different things with one finger and two or more fingers. My solution might need some tweak for you and i can't ensure everything will work exactly the same in your code-environment. I did not find proper documentation of hitTest and why it is called multiple times in a row. So i did some testing and came to a solution, how to separate one and multi-finger gestures, which worked very well for my needs.
I had this view hierarchy:
---> A superView
|
---> ScrollView - A - all touches
|
---> ScrollView - B - only two+ finger scroll (exactly on top of A, completely blocking A).
I implemented the switch in hitTest of the superView:
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;
}
}
I would suggest you to use below line of code where needed may help you out.
//--->for bview gesture to detect swipe
[pinch requireGestureRecognizerToFail:leftSwipe]; &&
[pinch requireGestureRecognizerToFail:rightSwipe];
//--->for aview gesture to detect pinch
[rightSwipe requireGestureRecognizerToFail:rightSwipe]; ||
[leftSwipe requireGestureRecognizerToFail:pinch];
If bView has pinch gesture. From bView's pinch gesture action if called aView's pinch gesture action then...
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=....
참조 URL : https://stackoverflow.com/questions/9209998/forwarding-uigesture-to-views-behind
'developer tip' 카테고리의 다른 글
실제 색상을 혼합하는 것과 같은 색상 혼합 알고리즘이 있습니까? (0) | 2020.12.26 |
---|---|
Apache에서 Clojure 웹 응용 프로그램을 통합하는 방법 (0) | 2020.12.26 |
null을 확장하는 클래스를 작성하는 방법과 이유는 무엇입니까? (0) | 2020.12.26 |
성능을 향상 시키려면 어떤 PHP opcode cacher를 사용해야합니까? (0) | 2020.12.26 |
이 이미지 처리 테스트에서 Swift가 C보다 100 배 느린 이유는 무엇입니까? (0) | 2020.12.26 |