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

UITextView占位符引发第二个字母自动大写及加载不显示问题

UITextView占位符功能异常修复方案

问题描述

实现了类似Twitter发帖界面的UITextView占位符功能,控件位于CollectionReusableView中,出现两个异常:

  • 输入时第二个字母自动大写
  • viewDidLoad时占位符不显示

原代码

lazy var textView: UITextView = {
    let view = UITextView()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.delegate = self
    view.text = "What's happening?"
    view.textColor = .lightGray
    view.textContainerInset = .zero
    view.textContainer.lineFragmentPadding = 0.0
    view.font = UIFont.systemFont(ofSize: 20)
    return view
}()

func textViewDidBeginEditing(_ textView: UITextView) {
    if textView.textColor == UIColor.lightGray {
        textView.text = nil
        textView.textColor = .label
    }
}

func textViewDidEndEditing(_ textView: UITextView) {
    if textView.text.isEmpty {
        textView.text = "What's happening?"
        textView.textColor = UIColor.lightGray
    }
}

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        let currentText: String = textView.text
        let updatedText = (currentText as NSString).replacingCharacters(in: range, with: text)
        if updatedText.isEmpty {
            textView.text = "What's happening?"
            textView.textColor = .lightGray
            textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)
        } else if textView.textColor == UIColor.lightGray && !text.isEmpty {
            textView.textColor = .label
            textView.text = text
        }
        else {
            return true
        }
        return false
}

func textViewDidChangeSelection(_ textView: UITextView) {
    if textView.textColor == UIColor.lightGray {
        textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)
    }
}

异常修复方案

1. 输入时第二个字母自动大写问题

问题出在shouldChangeTextIn方法的首次输入逻辑:直接用textView.text = text替换文本,跳过了系统默认的文本输入流程,导致自动大写的状态异常。

修改后的shouldChangeTextIn方法:

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    let currentText: String = textView.text
    let updatedText = (currentText as NSString).replacingCharacters(in: range, with: text)
    
    if updatedText.isEmpty {
        textView.text = "What's happening?"
        textView.textColor = .lightGray
        textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)
        return false
    } else if textView.textColor == UIColor.lightGray && !text.isEmpty {
        // 清空占位符,让系统处理首次输入流程
        textView.text = nil
        textView.textColor = .label
        return true
    } else {
        return true
    }
}

2. viewDidLoad时占位符不显示问题

CollectionReusableView的viewDidLoad不是布局完成的时机,UITextView的frame可能未正确初始化;同时复用控件时也需要重置占位符状态。

在你的CollectionReusableView类中添加以下代码:

override func layoutSubviews() {
    super.layoutSubviews()
    // 布局完成后确保占位符状态正确
    if textView.text.isEmpty || textView.textColor == .lightGray {
        textView.text = "What's happening?"
        textView.textColor = .lightGray
    }
}

override func prepareForReuse() {
    super.prepareForReuse()
    // 复用前重置占位符
    textView.text = "What's happening?"
    textView.textColor = .lightGray
    textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 03:45:34