33

いくつかの「サブビュー」を含む UIView (「コンテナー ビュー」) があります。UITapGestureRecognizer をコンテナー ビューに追加して、コンテナー ビューの内側でサブビューの外側の領域に触れたときにアクティブになるようにします。

現時点では、サブビュー内を含むコンテナー ビュー内の任意の場所に触れると、ジェスチャ レコグナイザーがアクティブになります。

実装は次のようになります。

ContainerView *containerView = [[ContainerView alloc] initWithSubViews:array];
UITapGestureRecognizer *tap = [UITapGestureRecognizer alloc] initWithTarget:self action:@selector(someSelector)];
[containerView addGestureRecognizer:tap];
[self.view addSubView:containerView];

ContainerView.m 内

-(id)initWithSubviews:(NSArray *)array {
    for (subView *s in array) {
        [self addSubView:s];
    }
    return self;
}

サブビューの後にジェスチャーレコグナイザーが追加されたため、問題が発生したと思います。それが本当なら、解決策として initWithSubViews メソッドを 2 つの別々のメソッドに分割する必要がありますが、これは避けたいと思います。

ありがとうございました

4

9 に答える 9

42

以下の簡単な方法を使用しました。それは完全に機能します!

UIGestureRecognizerDelegate 関数を実装し、スーパービューでのタッチのみを受け入れ、サブビューでのタッチを受け入れません。

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if (touch.view != _mySuperView) { // accept only touchs on superview, not accept touchs on subviews
        return NO;
    }

    return YES;
}
于 2013-09-19T04:45:42.133 に答える
15

iOS 6 では、まさにこの問題を解決する優れた新機能が導入されました。UIView (サブビュー) はgestureRecognizerShouldBegin:(スーパービューに接続されたジェスチャ認識エンジン) から NO を返すことができます。実際、一部のジェスチャ レコグナイザに関しては、既に一部の UIView サブクラスのデフォルトになっています (たとえば、スーパービューにアタッチされた UITapGestureRecognizer に関する UIButton)。

このトピックに関する私の本を参照してください: http://www.apeth.com/iOSBook/ch18.html#_gesture_recognizers

于 2013-03-18T04:27:17.897 に答える
13

次のようにして、なんとか機能させることができました。

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureHandler:)];

// ...

-(void) tapGestureHandler:(UITapGestureRecognizer *)sender {
    CGPoint point = [sender locationInView:sender.view];
    UIView *viewTouched = [sender.view hitTest:point withEvent:nil];
    if ([viewTouched isKindOfClass:[ThingIDontWantTouched class]]) {
        // Do nothing;
    } else {
        // respond to touch action
    }
}
于 2013-03-18T03:51:23.960 に答える
6

デリゲート メソッドを追加して設定することを忘れないでください-

UIViewController の .h ファイルにこのデリゲートを含めます

@interface YourViewController: UIViewController<UIGestureRecogniserDelegate>

次に、tapGesture オブジェクトを作成している場所 (たとえば、viewDidLoad 内)

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(actionMethodYouWantToHappenOnTap)];  

    tap.delegate = self;  //Remember to set delegate! Otherwise the delegate method won't get called.

    [self.view addGestureRecognizer:tap];

デリゲート メソッドを設定することを忘れないでくださいtap.delegate = self;。その後、タップのデリゲート メソッドがタップ時に起動します。

このメソッド内で、タップ ジェスチャ認識を使用する場合に処理します。私のコードでは、特定のサブビューが表示されている場合はタップを無視したかったのです。

-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{

     if (!mySubview.hidden){
     return NO;   //This fired if said subview was visible, though whatever the condition of where and when you want tap to work, can be handled within this delegate method.
     }

    return YES;
}

これが同じ問題を抱えている他の人に役立つことを願っています。私が見つけたデリゲート メソッドを忘れずに設定することは、見過ごされやすいものでした。

乾杯

于 2014-09-15T11:55:28.037 に答える
1

Swift5にアップデート

@Awais Hussainの答えはそれにぴったりです、

ジェスチャーで表示 -> Controller.view -> subView -> ViewThingI_DontWantToBeTouched

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

        let tap = UITapGestureRecognizer(target: self, action: #selector(ViewController.tapGestureHandler(_:)))

    }


    @objc
    func tapGestureHandler(_ sender: UITapGestureRecognizer){
        let point = sender.location(in: sender.view)
        if let viewTouched = sender.view?.hitTest(point, with: nil), viewTouched is ViewThingI_DontWantToBeTouched{
            ()
            // Do nothing;
        }
        else {
            // respond to touch action
        }
    }
}
于 2020-06-05T09:12:55.630 に答える
0

追加した:

もっといいことを考えただけです。

ハンドラーで

-(void)tapGestureHandler:(UITapGestureHandler)gesture

ジェスチャ.viewがスーパービューであるかどうかを確認します。サブビューがタップされた場合、サブビューを返します。

================================================== ==

スーパービュー内でオーバーライドすることをお勧めします。

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

これは、ジェスチャがビュー内にあるかどうかを判断するために呼び出されます

この質問への回答を参照して、デフォルトでどのように動作するかを確認してください。

iOSのイベント処理-hitTest:withEvent:とpointInside:withEvent:はどのように関連していますか?

ポイントがそのサブビューのいずれかにあるかどうかを確認できます。はいの場合はnilを返し、そうでない場合はselfを返します。

また

各サブビューに、何もしないタプジェスチャレコグナイザーを追加します。サブビューのジェスチャレコグナイザーは、デフォルトでそのスーパービューのジェスチャレコグナイザーをキャンセルします。ただし、サブビューが多い場合は、メモリフットプリントを監視します。

于 2013-03-17T06:38:32.703 に答える
0

ContainerView 用に追加した場合はUITapGestureRecognizer、ContainerView 全体で応答するはずです。サブビューは気にしません。

サブビューの位置にある場合は、ジェスチャーの場所を確認して、ジェスチャーアクションをスキップしてください。

- (void) tapGestureHandler:(UIGestureRecognizer *) gestureRecognizer {


    CGPoint tapPoint = [gestureRecognizer locationInView:nil]; 

   //check your tapPoint contains ur subview frame, skip.else do ur actions
}
于 2013-03-17T03:46:58.257 に答える