1

だから私はコンテナビューを持つView Controllerを持っています。コンテナー ビューには、ビュー コントローラーの親コントローラーでもあるナビゲーション コントローラーが組み込まれています。ストーリーボードは次のようになります。

ビュー コントローラ( mainViewController) --> ナビゲーション コントローラ --> ビュー コントローラ( contentViewController)

以下にストーリーボードのスクリーンショットを示します。

最初の矢印は、コンテナー ビューからナビゲーション コントローラーへの埋め込みセグエです。contentViewController2 番目の矢印は、ナビゲーション コントローラーのルート ビュー コントローラーを表す関係です。

mainViewControllercontentViewControllerは、 という名前の同じクラスのオブジェクトですtestViewController。UIViewController のサブクラスです。その実装は簡単です。IBActionメソッドは 3 つだけで、他には何もありません。実装コードは次のとおりです。

#import "TestViewController.h"

@implementation TestViewController

- (IBAction)buttonTapped:(id)sender {
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil
                                                    message:@"button is tapped"
                                                   delegate:self
                                          cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil];
    [alert show];
}

- (IBAction)barButtonTapped:(id)sender
{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil
                                                    message:@"bar button is tapped"
                                                   delegate:self
                                          cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil];
    [alert show];
}

- (IBAction)viewTapped:(id)sender {
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil
                                                    message:@"view is tapped"
                                                   delegate:self
                                          cancelButtonTitle:@"OK"
                                          otherButtonTitles: nil];
    [alert show];
}        
@end

のコンテナ ビューに Tap Gesture Recognizer を追加しましたmainViewController。コンテナビューがタップされたときにviewTapped:(id)senderメッセージを送信します。mainViewControllerのルートビューの中に、タップすると にメッセージをcontentViewController送るボタンがあります。また、ツールバーにはバーボタンがあり、タップするとメッセージが送信されます。最初のシーンは. アプリの実行中、バー ボタンのタッチ イベントのみがブロックされ、タッチ イベントはボタンによって正しく処理されることがわかりました。Apple のドキュメントRegulating the Delivery of Touches to Viewsには、次のように書かれています。buttonTapped:(id)sendercontentViewControllercontentViewControllerbarButtonTapped:(id)sendercontentViewControllermainViewController

単純なケースでは、タッチが発生すると、タッチ オブジェクトが UIApplication オブジェクトから UIWindow オブジェクトに渡されます。次に、ウィンドウは、ビュー オブジェクト自体にタッチを渡す前に、まず、タッチが発生したビュー (またはそのビューのスーパービュー) にアタッチされたジェスチャ レコグナイザーにタッチを送信します。

タッチイベントはボタンに渡されないと思いました。これは本当に私を混乱させました。誰かがこの動作を説明できますか? どうもありがとうございました。


ストーリーボードのスクリーンショット: 絵コンテ

4

1 に答える 1

4

iOSのイベント処理ガイド: イベント配信: レスポンダー チェーンの「レスポンダー チェーンは特定の配信パスに従う」セクションでは、タッチ イベントが最初にタッチされたビューに渡され、次にそのすべてのスーパービューに渡される方法について説明しています。ウィンドウ、そして最後にアプリケーション自体に。

プロジェクトのビュー階層を簡略化して表現すると、次のようになります。

mainViewController's Root View
  | mainViewController's Container View (has Tap Gesture Recognizer)
  |   | UINavigationController's Root View
  |   |   | contentViewController's View
  |   |   |   | UIButton ("Button")
  |   |   | UINavigationController's Toolbar View
  |   |   |   | UIToolbarTextButton ("Item")

...そのため、ボタンまたはツールバー ボタンをタップすると、mainViewController のコンテナー ビューの前に touch イベントを受け取ります。

ボタンのイベントが発生し、ツールバーのボタンが発生しない理由は、iOS のイベント処理ガイド: Gesture Recognizersの「他のユーザー インターフェイス コントロールとの対話」セクションに関連しているようです。

iOS 6.0 以降では、デフォルトのコントロール アクションにより、ジェスチャ レコグナイザーの動作が重複するのを防ぎます。たとえば、ボタンの既定のアクションは 1 回のタップです。ボタンの親ビューにシングル タップ ジェスチャ レコグナイザがアタッチされている場合、ユーザーがボタンをタップすると、ボタンのアクション メソッドがジェスチャ レコグナイザの代わりにタッチ イベントを受け取ります。

UIButtonこれは、 がタップ ジェスチャ レコグナイザをプリエンプトできる理由を説明しているように見えますが、ツールバー ボタンについて明確には何も述べていません。

UIToolbarButtonビュー階層を印刷すると、ツールバー ボタンがを直接継承するプライベート クラスである を使用して表されていることがわかりますUIControl。私たちの観察に基づいて、パブリックサブクラスUIToolbarButtonのようにジェスチャ レコグナイザーをプリエンプトしないと仮定します。UIControlそのtouchesCancelled:withEvent:メソッドをスウィズルしたところ、タップ ジェスチャ認識エンジンが起動した後に呼び出されることがわかりました。これは、iOS のイベント処理ガイド: ジェスチャ レコグナイザの「ジェスチャ レコグナイザがタッチを認識する最初の機会を取得する」セクションに基づいて期待されることのようです。彼らは次のように述べています。

...ジェスチャ レコグナイザーがタッチ ジェスチャを認識した場合、ウィンドウはタッチ オブジェクトをビューに配信せず、認識されたシーケンスの一部であった以前にビューに送信したタッチ オブジェクトもキャンセルします。

この動作を変更するにはいくつかの方法があり、どの方法を選択するかは最終目標によって異なります。ツールバーでのタッチを許可したい場合はUITouch、ジェスチャ レコグナイザーのデリゲートに送信されたgestureRecognizer:shouldReceiveTouch:ものがツールバーのフレーム内にあるかどうかを確認し、そうである場合は返すNOことができます。特にへのタッチをブロックするには、UIButtonおそらくサブクラス化が必要ですが、mainViewController の子ビュー コントローラーへのすべてのタッチをブロックする場合は、そのコンテナー ビューに透明なビューを追加できます。

于 2014-09-27T22:53:09.450 に答える