在覆盖 firstResponder 中调用 resignFirstResponder 不起作用

Posted

技术标签:

【中文标题】在覆盖 firstResponder 中调用 resignFirstResponder 不起作用【英文标题】:Calling resignFirstResponder doesn't work within overrides firstResponder 【发布时间】:2016-01-25 04:57:35 【问题描述】:

如何使用 UIResponder 聚焦激活的 UITextField?

代码如下:

//  customTextField.swift
import UIKit
class customTextField: UITextField 

override func becomeFirstResponder() -> Bool 
    if self.tag == 1 
        self.borderStyle = .Line
        self.superview?.viewWithTag(2)?.resignFirstResponder()
        self.superview?.viewWithTag(3)?.resignFirstResponder()
     else if self.tag == 2 
        self.borderStyle = .Line
        self.superview?.viewWithTag(1)?.resignFirstResponder()
        self.superview?.viewWithTag(3)?.resignFirstResponder()            
     else 
        self.borderStyle = .Line
        self.superview?.viewWithTag(1)?.resignFirstResponder()
        self.superview?.viewWithTag(2)?.resignFirstResponder()
    
    return true

override func resignFirstResponder() -> Bool 
    print("This is called")
    self.borderStyle = .None
    super.resignFirstResponder()
    return true

我想通过 View 的标签检查哪个文本字段是 firstResponder。然后如果其他 TextField 不应该被 resignFirstResponder 关注。

但是,当我在视图中触摸 textField 时,甚至不会调用 becomefirstResponder 代码块中的 resignFirstResponder

【问题讨论】:

为何如此关注resignFirstResponder?不是简单地成为第一响应者就辞去前响应者的职务吗? 感谢您的建议。我如何推荐前响应者? 查看下面的答案:它响应 Calling resignFirstResponder doesn't work 【参考方案1】:

不要破坏超类:传递消息

在覆盖系统消息的过程中,例如becomeFirstResponder,您可能会无意中禁用父类。最安全、无操作的becomeFirstResponder 是这样的:

override func becomeFirstResponder() -> Bool 
    return super.becomeFirstResponder()

省略super.becomeFirstResponder() 会影响UITextField

也让原始逻辑(何时成为或不成为响应者)顺其自然。始终响应 truefalse 会更改父类的行为,这可能会产生不良和不幸的副作用。

    override func becomeFirstResponder() -> Bool 
        let becomeFirstResponder = super.becomeFirstResponder()
        // Do stuff
        return becomeFirstResponder
    

不要复制操作系统

无需跟踪当前响应者。 让操作系统通知您谁是响应者:否则,当屏幕键盘在没有点击新字段的情况下被关闭时,尝试进行跟踪实际上可能无法正常工作,并且必然会中断。相反,请以相同的方式收听resignFirstResponder

override func resignFirstResponder() -> Bool 
    return super.resignFirstResponder()

更少的代码,更多的灵活性

将两个规则放在一起,并使用.RoundedRect.Line 进行显式重绘(.None 无效),您的整个CustomTextField 可能如下所示:

class CustomTextField: UITextField 

    override func becomeFirstResponder() -> Bool 
        let becomeFirstResponder = super.becomeFirstResponder()
        if becomeFirstResponder 
            self.borderStyle = .line
        
        return becomeFirstResponder
    

    override func resignFirstResponder() -> Bool 
        let resignFirstResponder = super.resignFirstResponder()
        if resignFirstResponder 
            self.borderStyle = .roundedRect
        
        return resignFirstResponder
    

请注意,如果 super.becomeFirstResponder()super.resignFirstResponder() 未成功,不会采取任何措施


演示


► 在GitHub 上查找此解决方案,在Swift Recipes 上查找更多详细信息。

【讨论】:

谢谢你。顺便说一句,我失败了。 Xcode 显示warning: could not load any Objective-C class information. This will significantly reduce the quality of type information available. 再次感谢您的帮助。我想我找到了我的项目不像你的那样工作的原因。在我的故事板中,我通过使用堆栈视图将每个标签和每个文本字段绑定在一起。然后我创建了三个堆栈视图。每个文本字段都在每个堆栈视图中。所以我认为在这种情况下你的代码不起作用。 这是我的项目的link。 self.borderStyle = .None 替换为self.borderStyle = .RoundedRect 您可能需要调整布局约束以使单元格的高度保持不变。 .None 有一个奇怪的行为,但 .RoundedRect 有效。

以上是关于在覆盖 firstResponder 中调用 resignFirstResponder 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

在 ModalView 中丢失 firstResponder

在 Cocoa Mac OSX 中设置 FirstResponder 的问题

防止 UITextField 在更改 firstResponder 时取值

通过包含另一个 firstResponder(一个 UITextView)来创建一个 firstResponder UIView

inputAccessoryView 中的 UITextField 不会成为FirstResponder

UITextField 辞职 firstResponder 太早了