37

1つの大きなuiviewの上に階層化された3つのUIViewがあります。ユーザーが一番上のものに触れて、他のものを気にしないかどうかを知りたいです。2番目のUIViewにいくつかのボタンがあり、3番目のUIViewにUITableがあります。

問題は、最初のビューでuserInteractionEngabledをオンにすると機能しますが、オフにしても他のすべてのビューは同じように応答します。self.viewでuserInteractionEnabledを無効にすると、いずれも応答しません。また、touchesBeganデリゲートメソッドでどのビューがタッチされたかを検出できません。

私のコード:

UIView *aView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 150)];
aView = userInteractionEnabled = YES;
[self.view addSubview:aView];

UIView *bView = [[UIView alloc] initWithFrame:CGRectMake(0, 150, 320, 50)];
bView.userInteractionEnabled = NO;
[self.view addSubview:bView];

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
//This gets called for a touch anywhere
}
4

8 に答える 8

64

別のビュー内の特定のビューがタッチされたかどうかを確認するには、hitTestを使用できます。

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;

touchesBeginのカスタム実装では、タッチセットのすべてのタッチをチェックします。hitTestメソッドのポイントは、次を使用して取得できます。

- (CGPoint)locationInView:(UIView *)view;

メソッド。ビューはsuperView(他のビューを含むビュー)です。

編集:これが高速なカスタム実装です:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
    CGPoint locationPoint = [[touches anyObject] locationInView:self];
    UIView* viewYouWishToObtain = [self hitTest:locationPoint withEvent:event];
}

これがお役に立てば幸いです、ポール

于 2010-05-08T07:15:50.993 に答える
30

私の場合、見つけたいUIViewがhitTestによって返されませんでした。ただし、次のコードの方がうまく機能しました。

    CGPoint locationPoint = [[touches anyObject] locationInView:self.view];
    CGPoint viewPoint = [myImage convertPoint:locationPoint fromView:self.view];
    if ([myImage pointInside:viewPoint withEvent:event]) {
       // do something
    }
于 2011-10-05T22:19:50.300 に答える
16

スウィフトコード:

 override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        if let touch = touches.first {
            if touch.view == self.view {
                self.hideInView()
            } else {
                return
            }

        }
    }
于 2016-06-16T09:43:05.197 に答える
15

これは、次の方法でも実行できます。

まず、気になるビューでタッチの場所を見つけます。

CGPoint location = [touches.anyObject locationInView:viewYouCareAbout];

次に、ポイントがビューの境界内にあるかどうかを確認します。

BOOL withinBounds = CGRectContainsPoint(viewYouCareAbout.bounds, location);

次に、範囲内にある場合は、アクションを実行します。

これは、1つのステートメントで実行できます。たとえば、ifステートメント内で直接使用できます。

CGRectContainsPoint(viewYouCareAbout.bounds, [touches.anyObject locationInView:viewYouCareAbout])
于 2013-09-04T16:23:59.257 に答える
8

touchesBeginで、タッチしたビューが目的のビューであることを確認し、ユーザーが特定のImageViewにタッチしたかどうかを識別しようとしたときに問題を解決しました。

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

    if ([touch view] ==  imageView ) {
        ... your code to handle the touch
    }
    ...

ビューのサイズのコンテンツを調整する場合は、それに応じてビューのサイズを変更してください。そうしないと、ビューにコンテンツが含まれている領域でもタッチイベントが認識されます。私の場合、UIViewContentModeScaleAspectFitで画像の比率を維持しようとすると、「空白」領域で必要に応じて画像が調整されましたが、タッチイベントもキャッチされました。

于 2013-02-20T09:55:04.100 に答える
7

タッチがinfoViewで行われたことを確認するための私の迅速なバージョン:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    guard let touch = touches.first, infoView.bounds.contains(touch.location(in: infoView))  else { return }
    print("touchesBegan") // Replace by your own code
} // touchesBegan
于 2018-04-09T18:47:57.333 に答える
0

これは私のために働いた:

func respondToGesture(gesture: UIGestureRecognizer) {
    let containsPoint = CGRectContainsPoint(targetView.bounds, gesture.locationInView(targetView))
}
于 2016-06-27T06:27:19.353 に答える
0

アプリケーションがタッチイベントを受信すると、ヒットテストプロセスが開始され、イベントを受信するビューを決定します。このプロセスは、ビュー階層のルート(通常はアプリケーションのウィンドウ)から始まり、タッチの下で最前面のビューが見つかるまで、前後の順序でサブビューを検索します。そのビューがヒットテストビューになり、タッチイベントを受け取ります。このプロセスに関係する各ビューは、最初にイベントの場所がその範囲内にあるかどうかをテストします。テストが成功した後でのみ、ビューはイベントをサブビューに渡して、さらにヒットテストを行います。したがって、ビューがタッチされているが、親ビューの境界の外側にある場合、親ビューはイベントの場所のテストに失敗し、タッチイベントをビューに渡しません。

この問題の解決策の1つは、ビューが親ビューの境界内に収まるようにビュー階層のレイアウトを変更することです。何らかの理由で既存のレイアウトを維持する必要がある場合は、親ビューのヒットテストの動作を変更して、タッチイベントを無視しないようにすることができます。これは、親ビューのクラスの-(UIView *)hitTest:withEvent:メソッドをオーバーライドすることで実行できます。

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {

    // Convert the point to the target view's coordinate system.
    // The target view isn't necessarily the immediate subview
    CGPoint pointForTargetView = [self.targetView convertPoint:point fromView:self];

    if (CGRectContainsPoint(self.targetView.bounds, pointForTargetView)) {

        // The target view may have its view hierarchy,
        // so call its hitTest method to return the right hit-test view
        return [self.targetView hitTest:pointForTargetView withEvent:event];
    }

    return [super hitTest:point withEvent:event]; }

この問題の他の考えられる原因は次のとおりです。

ビューまたはその親ビューのuserInteractionEnabledプロパティはNOに設定されます。アプリケーションは、endIgnoringInteractionEventsメソッドへの一致する呼び出しなしで、beginIgnoringInteractionEventsメソッドを呼び出しました。ビューをインタラクティブにする場合は、userInteractionEnabledプロパティがYESに設定されていること、およびアプリケーションがユーザーイベントを無視しないことを確認する必要があります。

ビューがアニメーション中にタッチイベントを受け取らない場合、それはUIViewのアニメーションメソッドが通常、アニメーションの進行中にタッチイベントを無効にするためです。UIViewアニメーションを開始するときに、UIViewAnimationOptionAllowUserInteractionオプションを適切に構成することで、この動作を変更できます。

別の解決策は

ビューに独自のカスタム実装を追加します

class CustomView: YourParentView {

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

        super.hitTest(point, with: event)
        return overlapHitTest(point: point, withEvent: event)
    }
}


extension UIView {

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

        // 1
        if !self.isUserInteractionEnabled || self.isHidden || self.alpha == 0 {

            return nil
        }

        // 2
        var hitView: UIView? = self
        if !self.point(inside: point, with: event) {

            if self.clipsToBounds {

                return nil
            } else {

                hitView = nil
            }
        }

        // 3
        for subview in self.subviews.reversed() {

            let insideSubview = self.convert(point, to: subview)
            if let sview = subview.overlapHitTest(point: insideSubview, withEvent: event) {
                return sview
            }
        }
        return hitView
    }
}
于 2019-05-01T16:35:27.807 に答える