[events] iOS-보기를 통해 모든 터치 전달

다른 많은보기 위에 오버레이 된보기가 있습니다. 나는 화면에서 몇 가지 터치를 감지하기 위해 Overaly를 사용하고 있지만 그 외에는 뷰가 스크롤 뷰와 같은 다른 뷰의 동작을 멈추고 싶지 않습니다. 모든 터치를 전달하는 방법 이 오버레이 뷰? UIView의 일부입니다.



답변

사용자 상호 작용을 비활성화하는 것만으로도 충분했습니다!

목표 -C :

myWebView.userInteractionEnabled = NO;

빠른:

myWebView.isUserInteractionEnabled = false


답변

오버레이보기에서 아래보기로 터치를 전달하려면 UIView에서 다음 메소드를 구현하십시오.

목표 -C :

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    NSLog(@"Passing all touches to the next view (if any), in the view stack.");
    return NO;
}

스위프트 5 :

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
    print("Passing all touches to the next view (if any), in the view stack.")
    return false
}


답변

이것은 오래된 스레드이지만 검색시 나왔으므로 2c를 추가 할 것이라고 생각했습니다. 하위보기가있는 덮는 UIView가 있고 하위보기 중 하나에 닿는 터치 만 가로 채기를 원하므로 PixelCloudSt의 답변을 다음과 같이 수정했습니다.

-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    for (UIView* subview in self.subviews ) {
        if ( [subview hitTest:[self convertPoint:point toView:subview] withEvent:event] != nil ) {
            return YES;
        }
    }
    return NO;
}


답변

@fresidue 답변의 개선 된 버전. 이 UIView서브 클래스는 서브 뷰 외부로 터치를 전달하는 투명한 뷰로 사용할 수 있습니다 . Objective-C의 구현 :

@interface PassthroughView : UIView

@end

@implementation PassthroughView

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    for (UIView *view in self.subviews) {
        if (!view.hidden && [view pointInside:[self convertPoint:point toView:view] withEvent:event]) {
            return YES;
        }
    }
    return NO;
}

@end

.

그리고 스위프트에서 :

class PassthroughView: UIView {
  override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
    return subviews.contains(where: {
      !$0.isHidden
      && $0.isUserInteractionEnabled
      && $0.point(inside: self.convert(point, to: $0), with: event)
    })
  }
}

팁:

그렇다면 테이블 뷰가있는 큰 “홀더”패널이 있다고 가정 해보십시오. “홀더”패널을 PassthroughView만듭니다. 이제 작동합니다. “홀더”를 통해 “테이블”을 스크롤 할 수 있습니다.

그러나!

  1. “보유자”패널 위에는 레이블이나 아이콘이 있습니다. 물론 사용자 상호 작용이 활성화 된 것으로 표시되어야합니다.

  2. “홀더”패널 위에는 몇 개의 버튼이 있습니다. 물론 사용자 상호 작용이 활성화 된 것으로 표시되어야합니다.

  3. 참고 사용하는보기 – 다소 혼동은 “홀더”자체 있음 PassthroughView에이 – 표시해야 사용자 상호 작용이 활성화 ON을 ! 그건 ON ! 그렇지 않으면 PassthroughView의 코드는 단순히 호출되지 않습니다.


답변

UIStackView와 비슷한 문제가 있었지만 다른보기 일 수 있습니다. 내 구성은 다음과 같습니다.
containerView 및 StackView가있는 View 컨트롤러

측면에 버튼이있는 배경에 배치해야 할 컨테이너가있는 고전적인 경우입니다. 레이아웃 목적으로 UIStackView에 버튼을 포함 시켰지만 이제 stackView의 중간 (빈) 부분이 터치를 차단합니다.

내가 한 것은 터치 할 수있는 subView를 정의하는 속성으로 UIStackView의 서브 클래스를 만드는 것입니다. 이제 사이드 버튼 (* viewsWithActiveTouch * 배열에 포함)을 터치하면 버튼이 표시되고,이 뷰 이외의 다른 곳에서 스택 뷰를 터치하면 가로 채지 않으므로 스택 아래에있는 모든 것에 전달됩니다. 전망.

/** Subclass of UIStackView that does not accept touches, except for specific subviews given in the viewsWithActiveTouch array */
class NoTouchStackView: UIStackView {

  var viewsWithActiveTouch: [UIView]?

  override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {

    if let activeViews = viewsWithActiveTouch {
        for view in activeViews {
           if CGRectContainsPoint(view.frame, point) {
                return view

           }
        }
     }
     return nil
   }
}


답변

터치를 전달하려는 뷰가 서브 뷰 / 슈퍼 뷰가 아닌 경우 UIView 서브 클래스에서 다음과 같이 사용자 정의 속성을 설정할 수 있습니다.

@interface SomeViewSubclass : UIView {

    id forwardableTouchee;

}
@property (retain) id forwardableTouchee;

당신의 .m에서 그것을 합성하십시오 :

@synthesize forwardableTouchee;

그런 다음과 같은 UIResponder 메소드에 다음을 포함하십시오.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    [self.forwardableTouchee touchesBegan:touches withEvent:event];

}

UIView를 인스턴스화 할 때마다 forwardableTouchee 속성을 이벤트를 전달할보기로 설정하십시오.

    SomeViewSubclass *view = [[[SomeViewSubclass alloc] initWithFrame:someRect] autorelease];
    view.forwardableTouchee = someOtherView;


답변

스위프트 5에서

class ThroughView: UIView {
    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        guard let slideView = subviews.first else {
            return false
        }

        return slideView.hitTest(convert(point, to: slideView), with: event) != nil
    }
}