UIView의 한계를 벗어난 상호작용
UI 버튼의 프레임이 상위 프레임 밖에 있을 때 UI 버튼(또는 이와 관련된 다른 컨트롤)이 터치 이벤트를 수신할 수 있습니까?왜냐하면 이걸 사용해보면 UI 버튼이 이벤트를 받을 수 없는 것 같습니다.이 문제를 해결하려면 어떻게 해야 합니까?
네. 당신은 그 다음에hitTest:withEvent:뷰에 포함된 것보다 큰 점 집합에 대해 뷰를 반환하는 메서드입니다.UIView Class Reference를 참조합니다.
편집: 예제:
- (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;
}
오버라이딩 포인트를 위해 바로 거기에 코드를 기록합니다.안이 정확하지 않습니다.아래 Summer에서 설명하는 대로 다음 작업을 수행합니다.
-(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으로, "oversize button"을의합니다."을 문제의 특수 뷰로 끌어다 놓으면 됩니다. (또는 어떤 이유로 프로젝트에서 이 작업을 많이 했다면 특별한 UIButton 하위 클래스가 있을 것이고, 해당 클래스에 대한 하위 뷰 목록을 살펴볼 수 있습니다.)도움이 되길 바랍니다.
@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]; }
제 경우의 컨테이너 뷰는 UI 버튼이며 모든 하위 요소는 상위 UI 버튼의 경계 밖으로 이동할 수 있는 UI 버튼이기도 합니다.
베스트
저 같은 경우에는.UICollectionViewCell가 포함된 하위 클래스.UIButton. 비활성화했습니다.clipsToBounds세포에 버튼이 세포의 경계 밖에서 보이는 겁니다그러나 이 버튼은 터치 이벤트를 수신하지 않았습니다.저는 잭의 답변 https://stackoverflow.com/a/30431157/3344977 을 사용하여 버튼의 터치 이벤트를 감지할 수 있었습니다.
스위프트 버전은 다음과 같습니다.
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)
}
상위 보기에서 히트 테스트 방법을 재정의할 수 있습니다.
- (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];
}
이 경우, 포인트가 단추의 테두리 안에 있으면 거기에 통화를 전달하고, 그렇지 않으면 원래 구현으로 돌아갑니다.
왜 이런 일이 일어날까요?
이는 하위 보기가 상위 보기의 범위를 벗어나는 경우 해당 하위 보기에서 실제로 발생하는 터치 이벤트가 해당 하위 보기에 전달되지 않기 때문입니다.그러나 그것은 그것의 수퍼뷰로 전달될 것입니다.
하위 보기가 시각적으로 잘리는지 여부에 관계없이 터치 이벤트는 항상 대상 보기의 경계 사각형을 존중합니다.즉, 수퍼뷰의 경계 사각형 밖에 있는 뷰의 일부에서 발생하는 터치 이벤트는 해당 뷰에 전달되지 않습니다. 링크
당신이 해야 할 일은?
당신의 수퍼뷰가 위에서 언급한 터치 이벤트를 수신할 때, 당신은 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. (Recall 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방법. 두 군데만 하면 됐어요두 곳에서만 해야 했어요.
Superview 이것은 만약 그것이clipsToBounds사실로 설정하면 이 모든 문제가 사라질 겁니다자, 여기 간단한 것이 있습니다.UIView스위프트 3:
class PromiscuousView : UIView {
override func point(inside point: CGPoint,
with event: UIEvent?) -> Bool {
return true
}
}
Subview 당신의 마일리지는 달라질 수 있지만, 제 경우에는 덮어쓰기를 해야 했습니다.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];
}
}
이 답변(그리고 동일한 질문에 대한 다른 답변)은 이해를 명료하게 하는 데 도움이 됩니다.
신속한 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)
}
이 질문이 오래된 질문이라는 것을 알고 있지만 여전히 업데이트된 버전으로 이러한 솔루션이 필요하기 때문에 이 문제의 새로운 버전 솔루션을 공유하고자 합니다.
생각해 봅시다.mainView틀은CGRect(0.0, 0.0, 250, 250.0)그리고 버튼 크기의 가로 세로 50인치를 추가하고 싶습니다.subView나의mainView(왼쪽 모서리 상단으로), 프레임은 다음과 같습니다.CGRect(-50, -50, 50, 50)인에mainView이 경우 우리는 이 버튼과 상호작용할 수 없으며 여기 이 문제를 해결하는 방법에 대한 예가 있습니다.
기본 보기(버튼 컨테이너 보기)에서 재정의hitTest다른 답변에서 언급된 것처럼 기능하지만 여기서 하위 뷰 순서를 바꾸고 히트 포인트를 이 하위 뷰 포인트로 변환한 다음 결과를 다음과 같이 확인합니다.hitTest당신의 뷰가 그 포인트를 포함하고 있는지 다시 확인합니다.mainView그렇지 않으면 다른 보기에 영향을 주지 않도록 0을 반환합니다.
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
guard !clipsToBounds && !isHidden && alpha > 0 else { return self.superview }
for member in subviews.reversed() {
let subPoint = member.convert(point, from: self)
guard let result = member.hitTest(subPoint, with: event) else { continue }
return result
}
return self.bounds.contains(point) ? self : nil
}
저는 이 코드를 제 앱에서 테스트해서 사용해보았는데 잘 작동합니다.
jnic의 답변 첫 부분의 스위프트 5 버전:
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let radius: CGFloat = 100
let frame = CGRect(
x: -radius,
y: -radius,
width: frame.width + radius * 2,
height: frame.height + radius * 2
)
if frame.contains(point) {
return self
}
return nil
}
언급URL : https://stackoverflow.com/questions/5432995/interaction-beyond-bounds-of-uiview
'programing' 카테고리의 다른 글
| MySQL은 업데이트 시 동일한 값의 열을 덮어씁니까? (0) | 2023.10.19 |
|---|---|
| Mac OS에서 MariaDB 5.5를 설치할 수 없습니다. (0) | 2023.10.19 |
| swift에서 textColor of UILabel 설정 방법 (0) | 2023.10.19 |
| 더블/플로트를 문자열로 변환 (0) | 2023.10.19 |
| 여러 프로젝트가 node_modules 디렉토리를 공유하도록 하려면 어떻게 해야 합니까? (0) | 2023.10.19 |