iOS Swift4:如何检测光标闪烁时长及实现编辑结束触发函数?
嘿,我来帮你拆解这两个问题,先从你实际遇到的痛点(结束编辑时调用特定函数)入手,再聊光标闪烁的检测问题~
一、解决“结束编辑而非编辑过程中调用函数”的需求
你之前用的textField(_:shouldChangeCharactersIn:replacementString:)和textFieldShouldEndEditing(_:)确实不符合需求:前者每次输入/删除字符都会触发(属于编辑过程中),后者是即将结束编辑时的回调(用来判断是否允许结束编辑,不是结束后的触发)。
正确的做法是使用UITextFieldDelegate的textFieldDidEndEditing(_:)方法——这个方法会在文本框完全结束编辑状态(比如用户点击Return键、点击页面其他区域让文本框失去焦点)之后被调用,完美匹配你的需求。
代码示例
class YourViewController: UIViewController, UITextFieldDelegate { override func viewDidLoad() { super.viewDidLoad() // 初始化文本框并设置代理 let inputTextField = UITextField(frame: CGRect(x: 20, y: 100, width: 300, height: 40)) inputTextField.borderStyle = .roundedRect inputTextField.delegate = self view.addSubview(inputTextField) } // 处理用户点击Return键的逻辑,让文本框失去焦点 func textFieldShouldReturn(_ textField: UITextField) -> Bool { textField.resignFirstResponder() return true } // 编辑结束后触发的核心方法,在这里调用你的特定函数 func textFieldDidEndEditing(_ textField: UITextField) { // 替换成你需要执行的函数 executeYourSpecificFunction() } // 你的自定义函数 private func executeYourSpecificFunction() { print("编辑已完成,执行特定操作!") // 这里写你的业务逻辑 } }
如果需要更精准的场景(比如区分用户是主动点击Return还是点击其他区域失去焦点),还可以结合textFieldDidEndEditing(_:reason:)(iOS 10+可用),通过UITextField.DidEndEditingReason来判断结束编辑的原因。
二、关于光标闪烁的检测问题
遗憾的是,Swift4(以及整个UIKit框架)并没有直接提供检测光标闪烁时长或状态的API——因为光标闪烁是系统层面的UI行为,UITextField/UITextView并没有暴露相关的属性或监听接口。
不过分两种情况处理:
1. 如果你只是想通过光标闪烁判断用户停止输入
完全不需要!上面的textFieldDidEndEditing(_:)已经能精准触发编辑结束的逻辑,比监听光标闪烁可靠得多。
2. 确实需要检测光标闪烁时长/状态
只能通过自定义光标的方式间接实现,自己控制闪烁逻辑,这样就能监控闪烁的时长和状态:
自定义光标代码示例
class CustomCaretTextField: UITextField { private var blinkTimer: Timer? private var isCaretVisible = true // 自定义闪烁周期(比如0.5秒亮,0.5秒暗) let blinkInterval: TimeInterval = 0.5 // 重写光标样式(可选,你可以自定义光标大小、颜色) override func caretRect(for position: UITextPosition) -> CGRect { let defaultRect = super.caretRect(for: position) // 调整光标高度和宽度 return CGRect(x: defaultRect.origin.x, y: defaultRect.origin.y + 3, width: 2, height: defaultRect.height - 6) } // 成为第一响应者时启动闪烁 override func becomeFirstResponder() -> Bool { let result = super.becomeFirstResponder() if result { startCaretBlinking() } return result } // 失去第一响应者时停止闪烁 override func resignFirstResponder() -> Bool { let result = super.resignFirstResponder() stopCaretBlinking() return result } // 启动闪烁定时器 private func startCaretBlinking() { stopCaretBlinking() blinkTimer = Timer.scheduledTimer(withTimeInterval: blinkInterval, repeats: true) { [weak self] _ in guard let self = self else { return } self.isCaretVisible.toggle() // 刷新光标显示 self.setNeedsDisplay() } } // 停止闪烁定时器 private func stopCaretBlinking() { blinkTimer?.invalidate() blinkTimer = nil isCaretVisible = true setNeedsDisplay() } }
通过这种方式,你可以完全控制光标闪烁的时长(blinkInterval),并且在isCaretVisible状态变化时添加自定义逻辑(比如记录闪烁次数、时长等)。
内容的提问来源于stack exchange,提问作者Rohini G

