首页 > 解决方案 > UITextField:attributeText 在 resignFirstResponder 时无法正常工作

问题描述

我有一个UITextField和一个按钮,该按钮突出显示文本字段文本的最后一个字母以及关闭键盘:

private func highlightLast() {
    guard let text = textField.text, text.count > 1 else {
        return
    }
    textField.resignFirstResponder()
    let attributedString = NSMutableAttributedString(string: text)
    attributedString.addAttribute(.backgroundColor, value: UIColor.yellow, range: NSRange(location: text.count - 1, length: 1))
    textField.attributedText = attributedString
}

第一次点击按钮可以正常工作,但如果我再次点击文本字段以显示键盘,然后再次点击按钮,整个文本都会突出显示:

稍作改动,无论我做了多少次,以下操作都可以正常工作:

  1. 在不关闭键盘的情况下突出显示最后一个字母或任何字母。
  2. 突出显示不是最后一个字母的任何字母,并关闭键盘。

这让我想知道我是否对范围做错了,或者其他一些基于键盘关闭的实现差异?

任何帮助表示赞赏!

更新:

我检查了视图层次结构,下面是它工作的时间(即仅突出显示最后一个字母)与它不工作的时间(即完全突出显示的文本):

当它按预期工作时:

Tes{
    NSBackgroundColor = "<UIDynamicSystemColor: 0x600001c89b40; name = systemBackgroundColor>";
    NSColor = "<UIDynamicSystemColor: 0x600001c8a780; name = labelColor>";
    NSFont = "<UICTFont: 0x7fad17d0c120> font-family: \".SFUI-Regular\"; font-weight: normal; font-style: normal; font-size: 14.00pt";
    NSParagraphStyle = "Alignment 4, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 4, Tabs (\n    28L,\n    56L,\n    84L,\n    112L,\n    140L,\n    168L,\n    196L,\n    224L,\n    252L,\n    280L,\n    308L,\n    336L\n), DefaultTabInterval 0, Blocks (null), Lists (null), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 65535";
    NSShadow = "NSShadow {0, -1} color = {(null)}";
}t{
    NSBackgroundColor = "UIExtendedSRGBColorSpace 1 1 0 1";
    NSColor = "<UIDynamicSystemColor: 0x600001c8a780; name = labelColor>";
    NSFont = "<UICTFont: 0x7fad17d0c120> font-family: \".SFUI-Regular\"; font-weight: normal; font-style: normal; font-size: 14.00pt";
    NSParagraphStyle = "Alignment 4, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 4, Tabs (\n    28L,\n    56L,\n    84L,\n    112L,\n    140L,\n    168L,\n    196L,\n    224L,\n    252L,\n    280L,\n    308L,\n    336L\n), DefaultTabInterval 0, Blocks (null), Lists (null), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 65535";
    NSShadow = "NSShadow {0, -1} color = {(null)}";
}

当整个文本突出显示不起作用时:

Test{
    NSBackgroundColor = "UIExtendedSRGBColorSpace 1 1 0 1";
    NSColor = "<UIDynamicSystemColor: 0x600001c8a780; name = labelColor>";
    NSFont = "<UICTFont: 0x7fad17d0c120> font-family: \".SFUI-Regular\"; font-weight: normal; font-style: normal; font-size: 14.00pt";
    NSParagraphStyle = "Alignment 4, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 4, Tabs (\n    28L,\n    56L,\n    84L,\n    112L,\n    140L,\n    168L,\n    196L,\n    224L,\n    252L,\n    280L,\n    308L,\n    336L\n), DefaultTabInterval 0, Blocks (null), Lists (null), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 65535";
    NSShadow = "NSShadow {0, -1} color = {(null)}";
}

标签: iosuikituitextfieldnsattributedstringresignfirstresponder

解决方案


来自 Apple 的文档

讨论

此属性默认为 nil。为该属性分配一个新值也会用相同的字符串数据替换 text 属性的值,尽管没有任何格式信息。此外,分配新值会更新字体、textColor 和其他与样式相关的属性中的值,以便它们反映从属性字符串中位置 0 开始的样式信息。

因此,您需要“重置”文本字段的属性。

一种方法:

override func viewDidLoad() {
    super.viewDidLoad()
    textField.addTarget(self, action: #selector(editingDidBegin(_:)), for: .editingDidBegin)
}

@objc func editingDidBegin(_ sender: Any) {
    let s = textField.text ?? ""
    textField.attributedText = NSAttributedString(string: s)
}

推荐阅读