ビュー階層は 内にありUIWindow
ます。は、そのメソッドUIWindow
でタッチ イベントを正しいビューに転送する責任があります。overridesendEvent:
のサブクラスを作りましょう。UIWindow
sendEvent:
@interface MyWindow : UIWindow
@end
ウィンドウには、現在のファーストレスポンダーが存在する場合、それへの参照が必要です。も使用する場合UITextView
があるので、テキスト フィールドとテキスト ビューの両方からの通知を確認します。
@implementation MyWindow {
UIView *currentFirstResponder_;
}
- (void)startObservingFirstResponder {
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(observeBeginEditing:) name:UITextFieldTextDidBeginEditingNotification object:nil];
[center addObserver:self selector:@selector(observeEndEditing:) name:UITextFieldTextDidEndEditingNotification object:nil];
[center addObserver:self selector:@selector(observeBeginEditing:) name:UITextViewTextDidBeginEditingNotification object:nil];
[center addObserver:self selector:@selector(observeEndEditing:) name:UITextViewTextDidEndEditingNotification object:nil];
}
- (void)stopObservingFirstResponder {
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center removeObserver:self name:UITextFieldTextDidBeginEditingNotification object:nil];
[center removeObserver:self name:UITextFieldTextDidEndEditingNotification object:nil];
[center removeObserver:self name:UITextViewTextDidBeginEditingNotification object:nil];
[center removeObserver:self name:UITextViewTextDidEndEditingNotification object:nil];
}
- (void)observeBeginEditing:(NSNotification *)note {
currentFirstResponder_ = note.object;
}
- (void)observeEndEditing:(NSNotification *)note {
if (currentFirstResponder_ == note.object) {
currentFirstResponder_ = nil;
}
}
ウィンドウは、初期化されると通知の監視を開始し、割り当てが解除されると停止します。
- (id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super initWithCoder:aDecoder])) {
[self commonInit];
}
return self;
}
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
[self commonInit];
}
return self;
}
- (void)commonInit {
[self startObservingFirstResponder];
}
- (void)dealloc {
[self stopObservingFirstResponder];
}
sendEvent:
イベントに基づいて最初のレスポンダーを「調整」するためにオーバーライドし、スーパーを呼び出しsendEvent:
てイベントを正常に送信します。
- (void)sendEvent:(UIEvent *)event {
[self adjustFirstResponderForEvent:event];
[super sendEvent:event];
}
ファーストレスポンダーがいない場合は、ファーストレスポンダーについて何もする必要はありません。ファーストレスポンダーがいて、タッチが含まれている場合、強制的に辞任させたくありません。(複数のタッチが同時に発生する可能性があることを覚えておいてください!) ファーストレスポンダーがあり、ファーストレスポンダーになる可能性のある別のビューに新しいタッチが表示された場合、システムはそれを自動的に正しく処理するため、そのケースも無視したいと考えています。しかし、ファーストレスポンダーがいて、タッチが含まれておらず、ファーストレスポンダーになれないビューに新しいタッチが表示された場合、ファーストレスポンダーを辞任させたいと考えています。
- (void)adjustFirstResponderForEvent:(UIEvent *)event {
if (currentFirstResponder_
&& ![self eventContainsTouchInFirstResponder:event]
&& [self eventContainsNewTouchInNonresponder:event]) {
[currentFirstResponder_ resignFirstResponder];
}
}
ファーストレスポンダーでイベントにタッチが含まれているかどうかを報告するのは簡単です。
- (BOOL)eventContainsTouchInFirstResponder:(UIEvent *)event {
for (UITouch *touch in [event touchesForWindow:self]) {
if (touch.view == currentFirstResponder_)
return YES;
}
return NO;
}
イベントにファーストレスポンダーにならない新しいタッチがビューに含まれているかどうかを報告するのは、ほぼ同じくらい簡単です。
- (BOOL)eventContainsNewTouchInNonresponder:(UIEvent *)event {
for (UITouch *touch in [event touchesForWindow:self]) {
if (touch.phase == UITouchPhaseBegan && ![touch.view canBecomeFirstResponder])
return YES;
}
return NO;
}
@end
このクラスを実装したら、 の代わりにこのクラスを使用するようにアプリを変更する必要がありますUIWindow
。
UIWindow
で作成する場合は、 の上部にあるapplication:didFinishLaunchingWithOptions:
必要があり、 の代わりにを作成するように変更します。#import "MyWindow.h"
AppDelegate.m
application:didFinishLaunchingWithOptions:
MyWindow
UIWindow
nib で作成する場合UIWindow
は、ウィンドウのカスタム クラスを nib に設定する必要がありますMyWindow
。