UIButton의 프레임이 부모의 프레임 밖에있을 때 UIButton (또는 그 문제에 대한 다른 컨트롤)이 터치 이벤트를받을 수 있습니까? 이 작업을 시도하면 UIButton이 이벤트를 수신 할 수없는 것 같습니다. 이 문제를 어떻게 해결합니까?
UIButton의 프레임이 부모의 프레임 밖에있을 때 UIButton (또는 그 문제에 대한 다른 컨트롤)이 터치 이벤트를받을 수 있습니까? 이 작업을 시도하면 UIButton이 이벤트를 수신 할 수없는 것 같습니다. 이 문제를 어떻게 해결합니까?
답변:
예. hitTest:withEvent:
메서드를 재정 의하여 해당 뷰에 포함 된 것보다 더 큰 점 집합에 대한 뷰를 반환 할 수 있습니다. 참고 항목 에 UIView 클래스 참조 .
편집 : 예 :
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
CGFloat radius = 100.0;
CGRect frame = CGRectMake(-radius, -radius,
self.frame.size.width + radius,
self.frame.size.height + radius);
if (CGRectContainsPoint(frame, point)) {
return self;
}
return nil;
}
편집 2 : (설명 후 :) 버튼이 부모의 경계 내에있는 것으로 처리되도록 pointInside:withEvent:
하려면 버튼의 프레임을 포함하도록 부모에서 재정의해야합니다 .
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
if (CGRectContainsPoint(self.view.bounds, point) ||
CGRectContainsPoint(button.view.frame, point))
{
return YES;
}
return NO;
}
참고 pointInside을 무시하는 것은 매우 정확하지 않습니다에 대한 그냥 거기에 코드를. 아래에 Summon이 설명하는대로 다음과 같이하십시오.
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
if ( CGRectContainsPoint(self.oversizeButton.frame, point) )
return YES;
return [super pointInside:point withEvent:event];
}
self.oversizeButton
이 UIView 하위 클래스에서 IBOutlet으로 수행 할 가능성이 매우 높습니다 . 그런 다음 문제의 "크기 초과 버튼"을 문제의 특수보기로 드래그 할 수 있습니다. (또는 어떤 이유로 프로젝트에서이 작업을 많이 수행했다면 특별한 UIButton 하위 클래스가 있고 해당 클래스에 대한 하위 뷰 목록을 살펴볼 수 있습니다.) 도움이되기를 바랍니다.
pointInside:withEvent:
버튼의 프레임을 포함하려면 부모를 재정의해야 합니다. 위의 답변에 샘플 코드를 추가하겠습니다.
hitTest:withEvent:
및 pointInside:withEvent:
지역 내가 버튼을 누를 때 나를 위해라는 부모의 경계의 거짓말의 외부 그.하지 무엇이 잘못 될 수 있습니까?
@jnic, 저는 iOS SDK 5.0에서 작업 중이며 코드가 올바르게 작동하도록하려면 다음을 수행해야합니다.
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
if (CGRectContainsPoint(button.frame, point)) {
return YES;
}
return [super pointInside:point withEvent:event]; }
필자의 경우 컨테이너 뷰는 UIButton이고 모든 자식 요소도 부모 UIButton의 경계 밖으로 이동할 수있는 UIButton입니다.
베스트
상위보기에서 적중 테스트 방법을 재정의 할 수 있습니다.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
CGPoint translatedPoint = [_myButton convertPoint:point fromView:self];
if (CGRectContainsPoint(_myButton.bounds, translatedPoint)) {
return [_myButton hitTest:translatedPoint withEvent:event];
}
return [super hitTest:point withEvent:event];
}
이 경우 포인트가 버튼 범위 내에 있으면 해당 지점에서 통화를 착신 전환합니다. 그렇지 않은 경우 원래 구현으로 되돌립니다.
제 경우 UICollectionViewCell
에는 UIButton
. 나는 clipsToBounds
셀을 비활성화 했고 버튼은 셀 경계 밖에서 보였습니다. 그러나 버튼이 터치 이벤트를받지 못했습니다. Jack의 답변 ( https://stackoverflow.com/a/30431157/3344977) 을 사용하여 버튼의 터치 이벤트를 감지 할 수있었습니다.
다음은 Swift 버전입니다.
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
let translatedPoint = button.convertPoint(point, fromView: self)
if (CGRectContainsPoint(button.bounds, translatedPoint)) {
print("Your button was pressed")
return button.hitTest(translatedPoint, withEvent: event)
}
return super.hitTest(point, withEvent: event)
}
스위프트 4 :
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let translatedPoint = button.convert(point, from: self)
if (button.bounds.contains(translatedPoint)) {
print("Your button was pressed")
return button.hitTest(translatedPoint, with: event)
}
return super.hitTest(point, with: event)
}
왜 이런 일이 발생합니까?
이는 서브 뷰가 수퍼 뷰의 경계 밖에있을 때 해당 서브 뷰에서 실제로 발생하는 터치 이벤트가 해당 서브 뷰로 전달되지 않기 때문입니다. 그러나, 그것은 것입니다 그 슈퍼 뷰에 전달 될 수있다.
하위 뷰가 시각적으로 잘리는 지 여부에 관계없이 터치 이벤트는 항상 대상 뷰 수퍼 뷰의 경계 사각형을 따릅니다. 즉, 수퍼 뷰의 경계 사각형 밖에있는 뷰의 일부에서 발생하는 터치 이벤트는 해당 뷰로 전달되지 않습니다. 링크
무엇을해야합니까?
수퍼 뷰가 위에서 언급 한 터치 이벤트를 수신하면 UIKit에 내 서브 뷰가이 터치 이벤트를 수신 할 수 있어야한다고 명시 적으로 알려야합니다.
코드는 어떻습니까?
수퍼 뷰에서 func hitTest(_ point: CGPoint, with event: UIEvent?)
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if isHidden || alpha == 0 || clipsToBounds { return super.hitTest(point, with: event) }
// convert the point into subview's coordinate system
let subviewPoint = self.convert(point, to: subview)
// if the converted point lies in subview's bound, tell UIKit that subview should be the one that receives this event
if !subview.isHidden && subview.bounds.contains(subviewPoint) { return subview }
return super.hitTest(point, with: event)
}
매혹적인 고치 야 : "가장 높은 너무 작은 슈퍼 뷰"로 가야합니다
문제보기가 외부에있는 "가장 높은"보기로 "위로"이동해야합니다.
전형적인 예 :
컨테이너 뷰 C가있는 화면 S가 있다고 가정 해 보겠습니다. 컨테이너 뷰 컨트롤러의 뷰는 V입니다. (리콜 V는 C 내부에 있으며 동일한 크기입니다.) V에는 하위 뷰가 있습니다 (아마도 버튼 일 수 있음) B. B가 문제입니다. 실제로 V 외부에있는보기입니다.
그러나 B도 C 외부에 있습니다.
이 예에서는 override hitTest
실제로 솔루션 을 V가 아닌 C 에 적용해야합니다 . V에 적용하면 아무것도하지 않습니다.
빠른:
여기서 targetView는 이벤트를 수신하려는 뷰입니다 (전체 또는 부분적으로 상위 뷰의 프레임 외부에 위치 할 수 있음).
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
let pointForTargetView: CGPoint = targetView.convertPoint(point, fromView: self)
if CGRectContainsPoint(targetView.bounds, pointForTargetView) {
return closeButton
}
return super.hitTest(point, withEvent: event)
}
나를 위해 (다른 사람)을, 대답이었다 하지 재정의하는 hitTest
방법, 오히려 pointInside
방법을. 나는 단지 두 곳에서만 이것을해야했다.
The Superview
이것이 clipsToBounds
참으로 설정하면이 모든 문제가 사라질 것이라는 견해입니다 . 그래서 여기 UIView
Swift 3의 간단한 것이 있습니다 .
class PromiscuousView : UIView {
override func point(inside point: CGPoint,
with event: UIEvent?) -> Bool {
return true
}
}
서브 뷰
마일리지는 다를 수 있지만, 제 경우 pointInside
에는 터치가 범위를 벗어났다고 결정한 서브 뷰에 대한 방법 도 덮어 써야 했습니다. 광산은 Objective-C에 있으므로 :
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
WEPopoverController *controller = (id) self.delegate;
if (self.takeHitsOutside) {
return YES;
} else {
return [super pointInside:point withEvent:event];
}
}
이 답변 (및 같은 질문에 대한 몇 가지 다른 답변)은 이해를 명확히하는 데 도움이 될 수 있습니다.
swift 4.1 업데이트
동일한 UIView에서 터치 이벤트를 얻으려면 다음과 같은 재정의 메서드를 추가하기 만하면됩니다. UIView에서 탭된 특정 뷰를 식별합니다.
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let pointforTargetview:CGPoint = self.convert(point, to: btnAngle)
if btnAngle.bounds.contains(pointforTargetview) {
return self
}
return super.hitTest(point, with: event)
}