다른 UIView 아래에있는 UIView의 버튼과 상호 작용을 허용하는 간단한 방법이 있습니까? 버튼 위에있는 상단 UIView의 실제 개체가없는 경우
예를 들어, 현재 화면 상단에는 개체가 있고 화면 하단에는 개체가 있고 중간에는 아무것도없는 UIView (A)가 있습니다. 이것은 가운데 (B)에 버튼이있는 다른 UIView 위에 있습니다. 그러나 B 중간에있는 버튼과 상호 작용할 수없는 것 같습니다.
B의 버튼을 볼 수 있습니다. A의 배경을 clearColor로 설정했지만 B의 버튼은 실제로 해당 버튼 위에 A의 개체가 없다는 사실에도 불구하고 터치를받지 않는 것 같습니다.
편집 -나는 여전히 상단 UIView의 객체와 상호 작용할 수 있기를 원합니다.
확실히 이것을하는 간단한 방법이 있습니까?
답변
상위 뷰에 대한 UIView 하위 클래스를 만들고 다음 메서드를 재정의해야합니다.
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
// UIView will be "transparent" for touch events if we return NO
return (point.y < MIDDLE_Y1 || point.y > MIDDLE_Y2);
}
hitTest : event : 메소드를 볼 수도 있습니다.
답변
여기에있는 많은 답변이 작동하지만, 가장 편리하고 일반적이며 완벽한 답변이 여기에 제공되지 않았다는 사실에 조금 놀랐습니다. @Ash가 가장 가까이 왔는데, 슈퍼 뷰를 반환하는 데 이상한 일이 벌어지고 있다는 점을 제외하면 … 그렇게하지 마세요.
이 답변은 유사한 질문에 대한 답변에서 가져온 것 입니다.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView *hitView = [super hitTest:point withEvent:event];
if (hitView == self) return nil;
return hitView;
}
[super hitTest:point withEvent:event]
터치 된 뷰의 계층 구조에서 가장 깊은 뷰를 반환합니다. If hitView == self
(즉, 터치 포인트 아래에 하위 뷰가없는 경우)를 반환 nil
하여이 뷰가 터치를 수신 하지 않도록 지정합니다 . 응답자 체인이 작동하는 방식은 터치에 응답 할보기를 찾을 때까지이 지점 위의보기 계층 구조가 계속 순회된다는 것을 의미합니다. 수퍼 뷰가 터치를 허용해야하는지 여부는이 뷰에 달려 있지 않으므로 수퍼 뷰를 반환 하지 마십시오 !
이 솔루션은 다음과 같습니다.
- 다른 뷰 / 하위 뷰 / 객체에 대한 참조가 필요하지 않기 때문에 편리 합니다.
- generic , 이는 순전히 터치 가능한 하위보기에 대한 컨테이너 역할을하는 모든보기에 적용되고 하위보기의 구성은 작동 방식에 영향을주지 않기 때문입니다 (
pointInside:withEvent:
특정 터치 가능 영역을 반환하도록 재정의 하는 경우처럼 ). - 완벽 하고 코드가 많지 않으며 개념은 머리를 돌리는 것이 어렵지 않습니다.
한 번의 재정의에 대해 무의미한 뷰 하위 클래스를 저장하기 위해 하위 클래스로 추상화 할만큼 자주 사용합니다. 보너스로 속성을 추가하여 구성 할 수 있습니다.
@interface ISView : UIView
@property(nonatomic, assign) BOOL onlyRespondToTouchesInSubviews;
@end
@implementation ISView
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView *hitView = [super hitTest:point withEvent:event];
if (hitView == self && onlyRespondToTouchesInSubviews) return nil;
return hitView;
}
@end
그런 다음 평범한 UIView
. 구성은로 설정 onlyRespondToTouchesInSubviews
하는 것만 큼 간단 합니다 YES
.
답변
이를 처리 할 수있는 방법에는 여러 가지가 있습니다. 필자가 가장 좋아하는 것은 충돌하는 뷰 (A와 B라고 부르는 것처럼 들림)에 대한 일반적인 수퍼 뷰 (간접적 일 수 있음) 인 뷰에서 hitTest : withEvent :를 재정의하는 것입니다. 예를 들어 다음과 같습니다 (여기서 A와 B는 UIView 포인터이며 B는 일반적으로 무시되는 “숨겨진”포인터입니다).
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
CGPoint pointInB = [B convertPoint:point fromView:self];
if ([B pointInside:pointInB withEvent:event])
return B;
return [super hitTest:point withEvent:event];
}
pointInside:withEvent:
김이 제안한 방법을 수정할 수도 있습니다 . 이렇게하면 최소한 터치에 대해 A에서 효과적으로 “구멍을 뚫음”으로써 본질적으로 동일한 결과를 얻을 수 있습니다.
또 다른 접근 방식은 이벤트 전달이며, 이는 처음 이동하는 위치와 다른 개체에 터치를 보내기 위해 재정의 touchesBegan:withEvent:
및 유사한 메서드 (예 : touchesMoved:withEvent:
etc)를 의미 합니다. 예를 들어 A에서 다음과 같이 작성할 수 있습니다.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if ([self shouldForwardTouches:touches]) {
[B touchesBegan:touches withEvent:event];
}
else {
// Do whatever A does with touches.
}
}
그러나 이것이 항상 예상대로 작동 하는 것은 아닙니다 ! 가장 중요한 것은 UIButton과 같은 기본 제공 컨트롤이 항상 전달 된 터치를 무시한다는 것입니다. 이 때문에 첫 번째 접근 방식이 더 안정적입니다.
이 모든 것을 더 자세히 설명하는 좋은 블로그 게시물과 아이디어를 시연하는 작은 xcode 프로젝트가 여기에 있습니다.
답변
을 설정해야합니다 upperView.userInteractionEnabled = NO;
. 그렇지 않으면 상단보기가 터치를 차단합니다.
이것의 Interface Builder 버전은 “User Interaction Enabled”라는 View Attributes 패널의 맨 아래에있는 확인란입니다. 체크를 해제하면 가셔도 좋습니다.
답변
pointInside : withEvent :의 사용자 정의 구현은 실제로 갈 길처럼 보였지만 하드 코딩 된 좌표를 다루는 것은 나에게 이상하게 보였습니다. 그래서 CGPoint가 CGRectContainsPoint () 함수를 사용하여 CGRect 버튼 안에 있는지 확인했습니다.
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
return (CGRectContainsPoint(disclosureButton.frame, point));
}
답변
최근에 저에게 도움이 될 수업을 썼습니다. UIButton
또는에 대한 사용자 정의 클래스로 사용하면 UIView
투명 픽셀에서 실행 된 터치 이벤트를 전달합니다.
이 솔루션은 UIButton
반투명 아래에있는 a 를 클릭 할 수 있지만의 투명 UIView
하지 않은 부분 UIView
은 여전히 터치 이벤트에 응답 할 수 있기 때문에 허용 된 답변보다 다소 낫습니다 .
GIF에서 볼 수 있듯이 Giraffe 버튼은 단순한 직사각형이지만 투명한 영역의 터치 이벤트는 UIButton
아래 의 노란색으로 전달됩니다 .
답변
이 파티에 조금 늦었지만 가능한 해결책을 추가하겠습니다.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *hitView = [super hitTest:point withEvent:event];
if (hitView != self) return hitView;
return [self superview];
}
이 코드를 사용하여 사용자 지정 UIView의 표준 hitTest 함수를 재정의하면보기 자체 만 무시됩니다. 해당 뷰의 모든 하위 뷰는 정상적으로 히트를 반환하고 뷰 자체로 이동했을 모든 히트는 수퍼 뷰로 전달됩니다.
-금연 건강 증진 협회
