【问题标题】:Swift- How to remove attributed string values and make it appear as normal string. (Bold, Italic, Underline, Strikethrough)Swift-如何删除属性字符串值并使其显示为普通字符串。 (粗体、斜体、下划线、删除线)
【发布时间】:2021-12-16 18:17:42
【问题描述】:

我想删除属性字符串值并使其显示为普通字符串。 (粗体、斜体、下划线、删除线)

我在下面添加了代码以使其具有属性,但我想知道当再次单击该操作时如何从字符串中删除这些属性。

Bold - 

   if textBold == true {
                            let string = text
                            let attributes: [NSAttributedString.Key: Any] = [
                                .font: UIFont.boldSystemFont(ofSize: 25)
                            ]
                            let attributedString = NSAttributedString(string: string, attributes: attributes)
                            modifiedString = attributedString
                            text_View.attributedText = modifiedString

                            text_View.sizeToFit()
                            databaseHandlerObj.editLabelData(textProjectId: fetchTextProjectId, text_Id: fetchTextId, text: modifiedString.string)
                        }

Italic - 
        if textItalic == true {

                            text_View.sizeToFit()
                            let string = text
                            
                            let attributes: [NSAttributedString.Key: Any] = [
                                .font: UIFont.italicSystemFont(ofSize: CGFloat(fontSize))
                            ]
                            let attributedString = NSAttributedString(string: string, attributes: attributes)
                            self.modifiedString = attributedString
                            text_View.attributedText = modifiedString
                            
                            databaseHandlerObj.editLabelData(textProjectId: fetchTextProjectId, text_Id: fetchTextId, text: modifiedString.string)
                        }

Underline -
   if textUnderline == true {
                            text_View.sizeToFit()
                            let string = text
                            let attributedString = NSMutableAttributedString.init(string: string)
                            attributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: 1, range:
                                                            NSRange.init(location: 0, length: attributedString.length))
                            self.modifiedString = attributedString
                            text_View.attributedText = modifiedString
                            
                            databaseHandlerObj.editLabelData(textProjectId: fetchTextProjectId, text_Id: fetchTextId, text: modifiedString.string)
                        }
                        

Strikethrough - 
      if textStrikethrough == true {
                            text_View.sizeToFit()
                            let string = text
                            let attributeString: NSMutableAttributedString =  NSMutableAttributedString(string: string)
                            attributeString.addAttribute(NSAttributedString.Key.strikethroughStyle, value: 2, range: NSMakeRange(0, attributeString.length))
                            self.modifiedString = attributeString
                            text_View.attributedText = modifiedString
                            databaseHandlerObj.editLabelData(textProjectId: fetchTextProjectId, text_Id: fetchTextId, text: modifiedString.string)
                        }

【问题讨论】:

    标签: swift string uilabel uitextview nsattributedstring


    【解决方案1】:

    您需要枚举NSAttributedString上的属性,并更改或删除它们。

    有一点帮助from another question to know if a font is bold/italic

    extension UIFont {
        var isBold: Bool {
            return fontDescriptor.symbolicTraits.contains(.traitBold)
        }
    
        var isItalic: Bool {
            return fontDescriptor.symbolicTraits.contains(.traitItalic)
        }
    }
    

    为了简化“你的真实逻辑”:

    extension NSAttributedString {
    
        enum Effects {
            case bold
            case italic
            case underline
            case strikethrough
        }
    
        var fullRange: NSRange {
            NSRange(location: 0, length: length)
        }
    }
    

    这应该可以解决问题:

    func remove(effects: NSAttributedString.Effects, on attributedString: NSAttributedString, range: NSRange) -> NSAttributedString {
    
        let mutableAttributedString = NSMutableAttributedString(attributedString: attributedString)
    
        mutableAttributedString.enumerateAttributes(in: range, options: []) { attributes, subrange, pointee in
            switch effects {
            case .bold:
                if let currentFont = attributes[.font] as? UIFont, currentFont.isBold {
                    let newFont = UIFont.systemFont(ofSize: currentFont.pointSize)
                    // Since we can only have one attribute at a range (and all subranges including in it)
                    // there is no need to remove then add, adding it will replace the previous one
                    mutableAttributedString.addAttribute(.font, value: newFont, range: subrange)
                }
            case .italic:
                if let currentFont = attributes[.font] as? UIFont, currentFont.isItalic {
                    let newFont = UIFont.systemFont(ofSize: currentFont.pointSize)
                    // Since we can only have one attribute at a range (and all subranges including in it)
                    // there is no need to remove then add, adding it will replace the previous one
                    mutableAttributedString.addAttribute(.font, value: newFont, range: subrange)
                }
            case .strikethrough:
                if attributes[.strikethroughStyle] != nil {
                    mutableAttributedString.removeAttribute(.strikethroughStyle, range: subrange)
                }
                if attributes[.strikethroughColor] != nil { 
                    mutableAttributedString.removeAttribute(.strikethroughColor, range: subrange)
                }
            case .underline:
                if attributes[.underlineColor] != nil {
                    mutableAttributedString.removeAttribute(.underlineColor, range: subrange)
                }
                if attributes[.underlineStyle] != nil {
                    mutableAttributedString.removeAttribute(.underlineStyle, range: subrange)
                }
            }
        }
        return mutableAttributedString
    }
    

    在 Playground 中,您可以使用以下方式进行测试:

    let boldText = NSAttributedString(string: "Bold text", attributes: [.font: UIFont.boldSystemFont(ofSize: 25)])
    let unboldText = remove(effects: .bold, on: boldText, range: boldText.fullRange)
    let italicText = NSAttributedString(string: "Italic text", attributes: [.font: UIFont.italicSystemFont(ofSize: 25)])
    let unItalicText = remove(effects: .italic, on: italicText, range: italicText.fullRange)
    let underlineText = NSAttributedString(string: "Underline text", attributes: [.underlineStyle: 1])
    let unUnderlineText = remove(effects: .underline, on: underlineText, range: underlineText.fullRange)
    let strikethroughText = NSAttributedString(string: "Strikethrough text", attributes: [.strikethroughStyle: 2])
    let unStrikethroughText = remove(effects: .strikethrough, on: strikethroughText, range: strikethroughText.fullRange)
    
    let attributedStrings = [boldText, unboldText, italicText, unItalicText, underlineText, unUnderlineText, strikethroughText, unStrikethroughText]
    
    let fullAttributedString = attributedStrings.reduce(into: NSMutableAttributedString()) {
        $0.append(NSAttributedString(string: "\n"))
        $0.append($1)
    }
    
    The following test is to ensure that if there are other effects on the `NSAttributedString`, they aren't removed.
    
    let textView = UITextView(frame: CGRect(x: 0, y: 0, width: 500, height: 200))
    textView.backgroundColor = .yellow
    textView.attributedText = fullAttributedString
    textView
    textView.attributedText = remove(effects: .bold, on: fullAttributedString, range: fullAttributedString.fullRange)
    textView
    textView.attributedText = remove(effects: .italic, on: fullAttributedString, range: fullAttributedString.fullRange)
    textView
    textView.attributedText = remove(effects: .underline, on: fullAttributedString, range: fullAttributedString.fullRange)
    textView
    textView.attributedText = remove(effects: .strikethrough, on: fullAttributedString, range: fullAttributedString.fullRange)
    textView
    

    注意事项: 您目前正在使用粗体或斜体,而不是同时使用两者,因为它在此属性中位于 UIFont 内,因此您需要同时找到粗体和斜体字体。
    所以如果你想从斜体和粗体中删除斜体,你需要得到粗体。我认为它是另一个范围,但对此存在疑问。

    注意事项 2:

    当你想删除属性时,我检查属性是否存在,但没有必要:

    所以:

    if attributes[.someAttribute] != nil {
        mutableAttributedString.removeAttribute(.someAttribute, range: subrange)
    }
    

    可能是:

    mutableAttributedString.removeAttribute(.someAttribute, range: subrange)
    

    注意事项 3:

    func remove(effects: NSAttributedString.Effects, on attributedString: NSAttributedString, range: NSRange) -> NSAttributedString
    

    可以改为NSAttributedString/NSMutableAttributedString 的扩展。

    【讨论】:

    • 感谢您的回答。它真的非常详细和易于理解。它对我有用。我还有一个关于在文本上保留属性组合的问题,我将单独发布。你能帮忙吗?
    【解决方案2】:

    您需要使用NSMutableAttributedString。在它上面,您可以使用 removeAttribute(_ name: NSAttributedString.Key, range: NSRange) 方法来指定范围,例如要删除属性的整个字符串。

    Apple documentation

    【讨论】:

    • 感谢您的回答。对我来说,它适用于下划线和删除线代码。但是如何对粗体和斜体文本进行所需的更改。如何在 NSMutableAttributedString 中添加它?
    • 难道只改变字体属性不就行了吗?
    • 没有。基本上我想提供自定义字体名称和字体大小。但它破坏了代码。有什么方法可以为粗体和斜体添加 NSMutableAttributedString
    猜你喜欢
    • 2022-01-17
    • 1970-01-01
    • 1970-01-01
    • 2014-03-01
    • 1970-01-01
    • 2011-05-06
    • 1970-01-01
    • 2018-05-18
    • 1970-01-01
    相关资源
    最近更新 更多