gpt4 book ai didi

ios - 在 UITextField 之外的任何地方触摸时关闭键盘

转载 作者:IT王子 更新时间:2023-10-29 07:53:46 26 4
gpt4 key购买 nike

我正在开发一个 iPad 应用程序,它有大量的 UIViewControllersUITableViews(带有 accessoryViews 的单元格 UITextFields) 等。许多 UIViewControllers 出现在导航层次结构中。

UITextFields 出现在许多不同的地方,包括 UITableViewCell accessoryViews

我想设计一种有效的策略,以便在用户触摸当前正在编辑的 UITextField 之外时关闭键盘。我搜索了键盘关闭技术,但尚未找到解释一般键盘关闭策略如何工作的答案。

例如,我喜欢这种方法,其中将以下代码添加到任何 ViewController:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(@"* * * * * * * * *ViewControllerBase touchesBegan");

[self.view endEditing:YES]; // dismiss the keyboard

[super touchesBegan:touches withEvent:event];
}

...但是此技术不处理以下情况,例如,在正在显示的 UITableView 中发生触摸。因此,我需要添加一些代码来在触摸 UITableView 时调用 endEditing 等等。这意味着我的应用程序将大量添加代码以触摸各种其他 UIElements 时关闭键盘。

我想我可以尝试找出所有需要拦截触摸和关闭键盘的不同位置,但在我看来,可能有更好的设计模式来处理 iOS 键盘关闭事件。

任何人都可以分享他们在这件事上的经验,并推荐一种在整个应用程序中通用处理键盘关闭的特定技术吗?

非常感谢

最佳答案

您的 View 层次结构位于 UIWindow 中。 UIWindow 负责将触摸事件转发到其 sendEvent: 方法中的正确 View 。让我们创建一个 UIWindow 的子类来覆盖 sendEvent:

@interface MyWindow : UIWindow
@end

如果有的话,窗口将需要对当前第一响应者的引用。您可能决定也使用 UITextView,因此我们会观察来自文本字段和 TextView 的通知。

@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:以根据事件“调整”第一响应者,然后调用super的sendEvent:正常发送事件。

- (void)sendEvent:(UIEvent *)event {
[self adjustFirstResponderForEvent:event];
[super sendEvent:event];
}

如果没有第一响应者,我们不需要对第一响应者做任何事情。如果有第一响应者,并且包含触摸,我们不想强制它辞职。 (记住,可以同时有多个触摸!)如果有一个第一响应者,并且另一个 View 中出现了一个可以成为第一响应者的新触摸,系统会自动正确处理,所以我们也想忽略这种情况。但是如果有一个第一响应者,并且它不包含任何触摸,并且一个新的触摸出现在一个不能成为第一响应者的 View 中,我们想让第一响应者辞职。

- (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;
}

在无法成为第一响应者的 View 中报告事件是否包含新触摸几乎同样简单:

- (BOOL)eventContainsNewTouchInNonresponder:(UIEvent *)event {
for (UITouch *touch in [event touchesForWindow:self]) {
if (touch.phase == UITouchPhaseBegan && ![touch.view canBecomeFirstResponder])
return YES;
}
return NO;
}

@end

实现此类后,您需要更改您的应用以使用它而不是 UIWindow

如果你在 application:didFinishLaunchingWithOptions: 中创建你的 UIWindow,你需要在顶部 #import "MyWindow.h"您的 AppDelegate.m,然后更改 application:didFinishLaunchingWithOptions: 以创建 MyWindow 而不是 UIWindow

如果您在 nib 中创建 UIWindow,则需要在 nib 中将窗口的自定义类设置为 MyWindow

关于ios - 在 UITextField 之外的任何地方触摸时关闭键盘,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11274119/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com