Swift中如何判断光标是否处于成对符号之间?iOS富文本快捷输入功能优化问询
解决iOS UITextView成对符号光标追踪问题
我明白你现在的核心痛点是:只用isShortcutBtnInputing这个布尔值没法精准判断光标是否还停留在插入的成对符号之间,导致用户手动移走光标后,回车逻辑依然触发跳转,不符合预期。
要解决这个问题,我们需要记录成对符号的具体位置范围,而不是依赖一个笼统的状态标记。下面是具体的实现方案:
1. 新增变量保存活跃符号范围
首先,在你的类里添加一个可选的NSRange变量,用来记录当前插入的成对符号在文本中的位置和长度:
var activeSymbolRange: NSRange? // 存储当前成对符号的完整范围
2. 修改快捷按钮点击方法,记录符号范围
更新shortcutFunc方法,在插入符号后计算并保存这个符号块的准确范围,同时去掉原来的isShortcutBtnInputing标记(用范围判断替代):
@objc func shortcutFunc(sender: CustomBtn, forEvent: UIEvent) { // 先确定当前编辑的TextView let selectedView: CustomTextView? = bodyViewUnderEditing ? textField.bodyView : titleViewUnderEditing ? textField.titleView : nil guard let selectedView = selectedView else { return } // 记录插入符号前的光标位置 let originalCursorLocation = selectedView.selectedRange.location // 插入成对符号 insertFromCursor(sender: sender, forEvent: forEvent) retreat = sender.retreat! // 计算成对符号的完整范围:从原光标位置开始,长度为插入的符号总长度 let totalSymbolLength = sender.argument!.count activeSymbolRange = NSRange(location: originalCursorLocation, length: totalSymbolLength) // 将光标移到成对符号中间 selectedView.selectedRange = NSRange(location: originalCursorLocation + retreat, length: 0) }
3. 更新回车逻辑,基于范围判断光标位置
修改textView(_:shouldChangeTextIn:replacementText:)方法,通过检查光标是否在activeSymbolRange范围内,来决定执行哪种回车逻辑:
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { if textView == textField.bodyView { if text == "\n", bodyViewUnderEditing { // 检查光标是否处于活跃的成对符号范围内 if let symbolRange = activeSymbolRange, NSLocationInRange(range.location, symbolRange) { // 光标在符号中间,跳转到符号末尾 let newCursorLocation = symbolRange.location + symbolRange.length textField.bodyView.selectedRange = NSRange(location: newCursorLocation, length: 0) activeSymbolRange = nil // 清空活跃范围,避免后续干扰 return false } else { // 光标不在符号内,执行普通换行 activeSymbolRange = nil return true } } // 额外处理:用户手动移动光标离开符号范围时,清空活跃标记 if let symbolRange = activeSymbolRange, !NSLocationInRange(textView.selectedRange.location, symbolRange) { activeSymbolRange = nil } return true } else if textView == textField.titleView { if text == "\n" { if let symbolRange = activeSymbolRange, NSLocationInRange(range.location, symbolRange), titleViewUnderEditing { // 跳转到符号末尾 let newCursorLocation = symbolRange.location + symbolRange.length textField.titleView.selectedRange = NSRange(location: newCursorLocation, length: 0) activeSymbolRange = nil } else { textField.bodyView.becomeFirstResponder() activeSymbolRange = nil } return false } // 手动移动光标离开符号范围时清空标记 if let symbolRange = activeSymbolRange, !NSLocationInRange(textView.selectedRange.location, symbolRange) { activeSymbolRange = nil } return true } return true }
方案说明
- 精准追踪:通过
activeSymbolRange记录成对符号的具体位置,替代原来的布尔标记,能准确判断光标是否在符号区域内。 - 自动重置状态:当用户手动将光标移出符号范围时,自动清空
activeSymbolRange,确保后续回车逻辑恢复正常。 - 边界处理:覆盖了用户在符号内输入、手动移走光标、按回车跳转等所有场景,逻辑更严谨。
内容的提问来源于stack exchange,提问作者Rex Zhang
相关产品推荐
相关产品推荐

