You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UITextView大小写显示切换与编辑时保留原字符串大小写的问题

解决UITextView显示变形字符串同时保留原字符串的问题

你的核心痛点在于:既要切换UITextView的显示大小写,又要准确维护用户输入的原始大小写字符串,而之前用shouldChangeTextIn的复杂逻辑导致了预测词输入等场景的异常。这里提供一个更简洁可靠的方案,核心思路是完全分离真实数据源和显示文本,统一处理所有编辑操作。

核心实现思路

  1. 用单独的变量保存用户输入的原始大小写字符串(作为真实数据源)。
  2. UITextView的显示文本仅根据开关状态,显示原始字符串的原格式或全大写格式。
  3. 在shouldChangeTextIn中直接利用系统传入的编辑参数更新原始数据源,再同步更新显示文本,同时手动维护光标位置,避免系统默认处理带来的冲突。

完整代码示例

import UIKit

class ViewController: UIViewController {
    lazy var textView: UITextView = {
        let txtv = UITextView(frame: CGRect(x: 0, y: 40, width: view.frame.width, height: 200))
        txtv.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        txtv.delegate = self
        txtv.font = UIFont.systemFont(ofSize: 22)
        return txtv
    }()
    
    lazy var toggleButton: UIButton = {
        let btn = UIButton(frame: CGRect(x: 20, y: 250, width: view.frame.width - 40, height: 50))
        btn.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        btn.setTitleColor(.blue, for: .normal)
        btn.setTitle("TOGGLE CAPITALIZATION", for: .normal)
        btn.addTarget(self, action: #selector(toggleCapitalizationState), for: .touchUpInside)
        return btn
    }()
    
    // 真实数据源:保存用户输入的原始大小写文本
    var originalText = "This is a test to see how we are doing"
    // 显示状态开关:是否以全大写显示
    var shouldShowUppercase = true
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(textView)
        view.addSubview(toggleButton)
        updateDisplayText()
    }
    
    /// 更新UITextView的显示文本
    private func updateDisplayText() {
        textView.text = shouldShowUppercase ? originalText.uppercased() : originalText
        // 保持光标位置不变,避免切换显示状态时光标跳走
        let currentCursorRange = textView.selectedRange
        textView.selectedRange = currentCursorRange
    }
    
    @objc private func toggleCapitalizationState() {
        shouldShowUppercase.toggle()
        updateDisplayText()
    }
}

extension ViewController: UITextViewDelegate {
    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        // 1. 更新原始数据源:直接利用系统传入的range和text修改原始文本
        let originalNSString = originalText as NSString
        originalText = originalNSString.replacingCharacters(in: range, with: text)
        
        // 2. 同步更新显示文本
        updateDisplayText()
        
        // 3. 手动维护光标位置:原range起始位置 + 替换文本的长度
        let newCursorLocation = range.location + text.count
        textView.selectedRange = NSRange(location: newCursorLocation, length: 0)
        
        // 禁止系统默认处理,避免和我们的手动更新冲突
        return false
    }
}

方案优势

  • 无hack逻辑:移除了原代码中针对预测输入的临时标记,所有编辑场景(普通输入、选中文本替换、预测词输入、删除操作)都能统一处理。
  • 数据源与显示解耦:原始文本和显示文本完全分离,不会出现大小写转换导致的不可逆问题。
  • 光标位置稳定:手动计算光标位置,确保编辑后光标始终处于预期位置,提升用户体验。

内容的提问来源于stack exchange,提问作者agibson007

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:42:21