如何为UITextField的自定义输入视图添加OTP视图并在自定义数字键盘中集成自动捕获OTP功能
实现自定义数字键盘的OTP视图集成与自动捕获功能
嘿,这两个需求其实在iOS开发里挺常见的,我帮你一步步拆解实现:
一、给自定义数字键盘添加OTP视图
首先咱们得把OTP输入/展示区域整合到你现有的MyCustomInputView里。一般OTP视图是由4-6个小输入框(或UILabel)组成的横向布局,用来接收用户的验证码输入。
1. 在MyCustomInputView中集成OTP视图
先在自定义输入视图类里添加OTP视图的属性,然后完成布局:
class MyCustomInputView: UIView { // 保留你原有的数字键盘按钮、代理等属性 weak var delegate: MyCustomInputViewDelegate? // 新增OTP视图(假设你已经封装了OTPInputView) let otpView = OTPInputView(frame: .zero) override init(frame: CGRect) { super.init(frame: frame) setupOTPView() setupNumberKeyboard() // 你原有的数字键盘布局方法 } required init?(coder: NSCoder) { super.init(coder: coder) setupOTPView() setupNumberKeyboard() } private func setupOTPView() { // 将OTP视图添加到自定义键盘顶部,调整布局参数适配你的需求 addSubview(otpView) otpView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ otpView.topAnchor.constraint(equalTo: topAnchor, constant: 20), otpView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20), otpView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20), otpView.heightAnchor.constraint(equalToConstant: 50) ]) // 设置OTP视图的代理,用来接收输入回调 otpView.delegate = self } }
2. 处理OTP视图的输入回调
给MyCustomInputView扩展实现OTP视图的代理方法,同步输入内容到关联的UITextField:
// 假设你的OTPInputView定义了如下代理协议 protocol OTPInputViewDelegate: AnyObject { func otpInputViewDidComplete(_ view: OTPInputView, code: String) func otpInputViewDidChange(_ view: OTPInputView, currentText: String) } extension MyCustomInputView: OTPInputViewDelegate { func otpInputViewDidComplete(_ view: OTPInputView, code: String) { // 通知代理完成输入 delegate?.customInputViewDidFinishOTPInput(code: code) // 同步内容到绑定的UITextField if let textField = self.superview?.superview as? UITextField { textField.text = code } } func otpInputViewDidChange(_ view: OTPInputView, currentText: String) { // 实时同步内容到UITextField if let textField = self.superview?.superview as? UITextField { textField.text = currentText } } }
3. 关联数字键盘按钮与OTP视图
在你原有的数字键盘按钮点击事件里,把输入的数字传递给OTP视图:
extension MyCustomInputView { // 数字按钮点击方法 @objc private func numberButtonTapped(_ sender: UIButton) { guard let number = sender.titleLabel?.text else { return } otpView.addCharacter(number) } // 删除按钮点击方法 @objc private func deleteButtonTapped(_ sender: UIButton) { otpView.deleteLastCharacter() } }
这里的addCharacter(_:)和deleteLastCharacter()需要你在OTPInputView里实现,逻辑是:输入数字时填充到下一个空输入框,删除时清空当前输入框并跳回上一个。
二、集成自动捕获OTP功能
iOS里自动捕获验证码有两种主流实现方式,推荐优先用系统原生的自动填充,无需额外权限体验更好。
方式一:系统原生自动填充(iOS12+,推荐)
- 给你的UITextField设置
textContentType为oneTimeCode,让系统识别短信中的验证码:
textField.textContentType = .oneTimeCode
- 监听UITextField的文本变化,把系统自动填充的验证码同步到OTP视图:
class YourViewController: UIViewController { @IBOutlet weak var textField: UITextField! override func viewDidLoad() { super.viewDidLoad() let inputView = MyCustomInputView() textField.inputView = inputView inputView.delegate = self // 开启自动填充支持 textField.textContentType = .oneTimeCode // 监听文本变化事件 NotificationCenter.default.addObserver( self, selector: #selector(textFieldTextDidChange(_:)), name: UITextField.textDidChangeNotification, object: textField ) } @objc private func textFieldTextDidChange(_ notification: Notification) { guard let textField = notification.object as? UITextField, let code = textField.text, !code.isEmpty else { return } // 同步验证码到自定义键盘的OTP视图 if let customInputView = textField.inputView as? MyCustomInputView { customInputView.otpView.setCode(code) } } }
- 在
OTPInputView里实现setCode(_:)方法,把验证码填充到对应的输入框中。
方式二:监听短信通知(iOS10+,需要通知权限)
如果系统自动填充无法满足需求,可以通过监听短信通知提取验证码:
- 先请求用户的通知权限:
import UserNotifications class YourViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // 请求通知权限 UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { granted, error in if granted { DispatchQueue.main.async { UIApplication.shared.registerForRemoteNotifications() } } } UNUserNotificationCenter.current().delegate = self } }
- 实现通知代理方法,提取短信中的验证码:
extension YourViewController: UNUserNotificationCenterDelegate { func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { completionHandler([.banner]) // 提取短信内容 let smsContent = notification.request.content.body // 用正则匹配6位数字验证码(根据你的实际验证码位数调整) let regexPattern = "\\d{6}" guard let regex = try? NSRegularExpression(pattern: regexPattern), let match = regex.firstMatch(in: smsContent, range: NSRange(location: 0, length: smsContent.count)) else { return } let code = (smsContent as NSString).substring(with: match.range) // 填充到OTP视图 DispatchQueue.main.async { if let customInputView = self.textField.inputView as? MyCustomInputView { customInputView.otpView.setCode(code) } } } }
注意:这种方式需要用户授权通知权限,且要适配不同运营商的短信格式,正则表达式可能需要调整。
内容的提问来源于stack exchange,提问作者Saranjith




