如何让自定义键盘适配TextField的AutocapitalizationType设置?
自定义键盘适配UITextField的AutocapitalizationType判断方法
要让自定义键盘适配输入控件的AutocapitalizationType设置,核心是通过键盘的输入代理获取当前控件的自动大写规则,再根据规则判断输入时机是否需要大写。具体实现步骤如下:
1. 获取当前输入控件的自动大写类型
自定义键盘的UIInputViewController中,通过textDocumentProxy(遵循UITextInputTraits协议)可以直接拿到目标控件的autocapitalizationType,对应的枚举值有四种:.none、.words、.sentences、.allCharacters。
2. 针对不同类型的判断逻辑
根据拿到的类型,分别处理大写触发条件:
- .allCharacters:所有输入字符强制大写,无需额外判断,直接将输入字符转大写即可。
- .none:所有字符保持小写,不做大写处理。
- .words:单词首字母大写
需要判断光标前的最后一个字符是否为单词分隔符(空格、标点、换行等),或者光标处于输入起始位置。可通过documentContextBeforeInput获取光标前的文本,再检查字符类型:let context = textDocumentProxy.documentContextBeforeInput ?? "" let separators = CharacterSet.whitespacesAndNewlines.union(.punctuationCharacters) let shouldCapitalize = context.isEmpty || separators.contains((context.last?.unicodeScalars.first)!) - .sentences:句子首字母大写
需要判断光标前的文本是否以句子结束符(句号、问号、感叹号,可后跟空格)结尾,或光标处于输入起始位置。可以用正则或字符匹配实现:let context = textDocumentProxy.documentContextBeforeInput ?? "" guard !context.isEmpty else { return true } // 正则匹配句子结束符后的位置 let regex = try? NSRegularExpression(pattern: #"(?<=[.!?]\s*)$"#) let range = NSRange(location: 0, length: context.utf16.count) let hasSentenceEnd = regex?.firstMatch(in: context, range: range) != nil // 兜底的简单判断 let lastChar = context.last! let secondLastChar = context.count >= 2 ? context[context.index(context.endIndex, offsetBy: -2)] : Character("") let simpleCheck = [".", "?", "!"].contains(lastChar) || ([".", "?", "!"].contains(secondLastChar) && lastChar.isWhitespace) let shouldCapitalize = hasSentenceEnd || simpleCheck
3. 整合逻辑并应用
可以封装一个工具方法,统一判断当前输入是否需要大写:
func shouldCapitalizeCurrentInput() -> Bool { guard let proxy = textDocumentProxy as? UITextInputTraits else { return false } let autocapType = proxy.autocapitalizationType switch autocapType { case .allCharacters: return true case .words: let context = proxy.documentContextBeforeInput ?? "" let separators = CharacterSet.whitespacesAndNewlines.union(.punctuationCharacters) if context.isEmpty { return true } return separators.contains((context.last?.unicodeScalars.first)!) case .sentences: let context = proxy.documentContextBeforeInput ?? "" if context.isEmpty { return true } let regex = try? NSRegularExpression(pattern: #"(?<=[.!?]\s*)$"#) let range = NSRange(location: 0, length: context.utf16.count) if regex?.firstMatch(in: context, range: range) != nil { return true } let lastChar = context.last! if [".", "?", "!"].contains(lastChar) { return true } if context.count >= 2 { let secondLastChar = context[context.index(context.endIndex, offsetBy: -2)] if [".", "?", "!"].contains(secondLastChar) && lastChar.isWhitespace { return true } } return false case .none: return false @unknown default: return false } }
在处理用户输入时(比如点击字母键),调用这个方法,返回true则输入大写字符,否则输入小写。
注意事项
- 优先尊重用户手动切换的大小写状态(比如用户点击了大写锁定键),此时应忽略自动大写规则。
documentContextBeforeInput返回的是光标前的有限文本,对于超长文本的句子判断,依赖最近的几个字符即可满足大部分场景需求。
内容的提问来源于stack exchange,提问作者Sándor Tatai
相关产品推荐
相关产品推荐

