2011-10-10 3 views
55

UIViewが画面の角を占めるカスタムUIViewControllerを持っていますが、そのほとんどは透明です。そのビュー上のオブジェクトのレイアウトのため、ビューのフレームは、その下のいくつかのボタンを隠すことができます。私は、その上で重要な何かに触れていない場合は、そのビューのタッチを無視することができるようにしたいが、私は実際のタッチイベント(touchesEnded/nextResponderもの)に沿って渡すことができるようだ。 UIButtonやそれ以外のものがある場合は、どうすればそのタッチイベントを渡すことができますか?タッチイベントを無視して別のサブビューのUIControlオブジェクトに渡す方法はありますか?

このカスタムViewControllerをさまざまなビューで使用できるため、ボタンセレクタを呼び出すだけで手動で判断することはできません。同様Uicontrolのタイプの

[self.nextResponder touchesEnded:touches withEvent:event];

:私は基本的にこれを呼び出すための方法が必要です。

答えて

120

おそらくこれを行うための最善の方法は、あなたのビューでhitTest:withEvent:をオーバーライドすることですタッチを無視したいビュー階層の複雑さによっては、これを行う簡単な方法がいくつかあります。

あなたは無視するビューの下に図を参照している場合:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 
{ 
    UIView *hitView = [super hitTest:point withEvent:event]; 

    // If the hitView is THIS view, return the view that you want to receive the touch instead: 
    if (hitView == self) { 
     return otherView; 
    } 
    // Else return the hitView (as it could be one of this view's buttons): 
    return hitView; 
} 

を使用すると、図を参照していない場合:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 
{ 
    UIView *hitView = [super hitTest:point withEvent:event]; 

    // If the hitView is THIS view, return nil and allow hitTest:withEvent: to 
    // continue traversing the hierarchy to find the underlying view. 
    if (hitView == self) { 
     return nil; 
    } 
    // Else return the hitView (as it could be one of this view's buttons): 
    return hitView; 
} 

を、私は最初のアプローチをお勧めします最も堅牢なものとして表示されます(基になるビューへの参照を取得できる場合)。

+0

これは私がやりたがっているようですが、タッチを無視したいビューは私が作成したUIViewControllerのビュープロパティです。そのビューのhitTest関数をオーバーライドする方法はありますか? –

+4

@chris:もちろん、サブクラス化して上記のようにオーバーライドされたメソッドを投げるだけです。これは、余分な '.h'と' .m'ファイルを少しだけコードで囲んでいることを意味しますが、それは仕事をするでしょう。また、パススルービューは、ツールキットに含めるのに便利なサブクラスです。 View Controllerが 'nib'でビューを作成する場合は、IBファイルに入り、IDインスペクタでビューのクラスを新しいサブクラスに変更します。プログラムによって作成された場合は、 'loadView'でビューサブクラスを作成して割り当てます(編集を参照)。 – Stuart

+0

素敵なアドバイス!私は一日中良い解決策を探してきました。ありがとう。 – Judioo

7

オブジェクト間でUITouchイベントを渡すための良い方法が見つかりませんでした。どのような通常良い作品は、hitTestを実装し、ポイントは、あなたがそれを処理するビューでない場合はnilを返すことです:

​​
3

これは古い質問であり、検索の先頭に表示されます。だから、私は自分の状況に適した別の解決策を投稿するつもりだと思った。私の場合、別のラベルの上にラベルをドラッグしたいと思っていました。私は、下のラベルをhitTestに入れたいと思っていました。最も簡単な方法は、userInteractionEnabledNOまたはfalseに設定してからhitTestを実行し、再度移動する必要がある場合は再度設定することです。

override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) { 
    let touch = touches.first 
    let location = touch?.locationInView(self.view) 
    self.label1.userInteractionEnabled = false 
    let view = self.view.hitTest(location!, withEvent: nil) as? UILabel 
    print(view?.text) 
    self.label1.userInteractionEnabled = true 
} 
+0

解決に感謝します。 – Hiren

+0

これは、label1.userInteractionEnabledをfalseに設定すると、label1は後でtouchを検出しなくなるため動作しません。 –

+0

@FredA。だから、私はこう書いています: "...そして、あなたがもう一度それを動かす必要があるなら、それを再びセットしてください"。多分私は十分にはっきりしていなかったでしょうか? – smileBot

8

スウィフト答え:

あなたは、IgnoreTouchViewをUIViewのサブクラスを作成することができます。ここスウィフトのコードサンプルです。あなたが問題になっているのUIViewのために、trueにUserInteractionEnabledを設定する必要があります

class IgnoreTouchView : UIView { 
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { 
     let hitView = super.hitTest(point, with: event) 
     if hitView == self { 
      return nil 
     } 
     return hitView 
    } 
} 

注:ストーリーボードでは、あなたがタッチを通過したいVCのビュー(複数可)の上に置きます!

これは、とき、親スクロールを防ぐ(または他の相互作用を防ぐために変更することができます)...私は複雑なタッチレスポンダとUicontrolのがあったが、スクロールビューに埋め込まれたときにそれが面白い行動:

+0

ケビン、私は最新のスウィフトバージョン、April2017にいくつかの文字を編集しました。 (気軽に変更するなど)乾杯 – Fattie

0

私の問題は類似していましたサブビューにはアクティブなタッチジェスチャーがあります。

私のソリューション:

サブビューでdidBeginInteractionとdidEndInteractionためのデリゲートプロトコルを作成します。 touchesBegan

から

コールdelegate.didBeginInteraction

コールtouchesEndedからdelegate.didEndInteraction親コントローラで

をtouchesCancelled、実装didBeginとdidEndプロトコル、設定デリゲート

その後にNO = scrollView.scrollEnabledを設定しますdidBegin、scrollEnabled = didEndのYESです。

これは、質問とは多少異なるユースケースを持つ人に役立ちます。

関連する問題