替换NSAttributedString中的整个文本字符串而不修改其他属性

时间:2015-05-15 19:44:52

标签: ios objective-c nsattributedstring

我有NSAttributedString的引用,我想更改属性字符串的文本。

我想我必须创建一个新的NSAttributedString并使用这个新字符串更新引用。但是,当我这样做时,我失去了之前字符串的归属。

NSAttributedString *newString = [[NSAttributedString alloc] initWithString:text];
[self setAttributedText:newString];

我在self.attributedText中引用了旧的属性字符串。如何保留新字符串中的先前属性?

9 个答案:

答案 0 :(得分:33)

您可以使用NSMutableAttributedString并只更新字符串,这些属性不会发生变化。 例如:

NSMutableAttributedString *mutableAttributedString = [[NSMutableAttributedString alloc] initWithString:@"my string" attributes:@{NSForegroundColorAttributeName: [UIColor blueColor], NSFontAttributeName: [UIFont systemFontOfSize:20]}];

//update the string
[mutableAttributedString.mutableString setString:@"my new string"];

答案 1 :(得分:29)

夫特

在保留属性的同时更改文本:

let myString = "my string"
let myAttributes = [NSAttributedString.Key.foregroundColor: UIColor.blue, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 40)]
let mutableAttributedString = NSMutableAttributedString(string: myString, attributes: myAttributes)

let myNewString = "my new string"
mutableAttributedString.mutableString.setString(myNewString)

mutableAttributedString的结果是

  • enter image description here
  • enter image description here

备注

丢弃索引0之外的任何子范围。例如,如果我将另一个属性添加到原始字符串的最后一个单词,则在更改字符串后它将丢失:

// additional attribute added before changing the text
let myRange = NSRange(location: 3, length: 6)
let anotherAttribute = [ NSAttributedString.Key.backgroundColor: UIColor.yellow ]
mutableAttributedString.addAttributes(anotherAttribute, range: myRange)

结果:

  • enter image description here
  • enter image description here

从中我们可以看到新字符串获取原始字符串索引0处的属性。实际上,如果我们将范围调整为

let myRange = NSRange(location: 0, length: 1)

我们得到了

  • enter image description here
  • enter image description here

另见

答案 2 :(得分:4)

我做了一点扩展,让这很容易:

import UIKit

extension UILabel {
    func setTextWhileKeepingAttributes(string: String) {
        if let newAttributedText = self.attributedText {
            let mutableAttributedText = newAttributedText.mutableCopy()

            mutableAttributedText.mutableString.setString(string)

            self.attributedText = mutableAttributedText as? NSAttributedString
        }
    }
}

https://gist.github.com/wvdk/e8992e82b04e626a862dbb991e4cbe9c

答案 3 :(得分:2)

这是使用Objective-C的方式(在iOS 9上测试)

NSAttributedString *primaryString = ...;
NSString *newString = ...;

//copy the attributes
NSDictionary *attributes = [primaryString attributesAtIndex:0 effectiveRange:NSMakeRange(primaryString.length-1, primaryString.length)];
NSMutableAttributedString *newString = [[NSMutableAttributedString alloc] initWithString:newString attributes:attributes];
NSMutableAttributedString *primaryStringMutable = [[NSMutableAttributedString alloc] initWithAttributedString:primaryString];

//change the string
[primaryStringMutable setAttributedString::newString];

primaryString = [NSAttributedString alloc] initWithAttributedString:primaryStringMutable];

检查最重要的参考文献:attributesAtIndex:effectiveRange:setAttributedString:

答案 4 :(得分:1)

大流士的回答几乎就在那里。它包含一个小错误。正确的是:

这是使用Objective-C的方式(在iOS 10上测试)

NSAttributedString *primaryString = ...;
NSString *newString = ...;

//copy the attributes
NSRange range = NSMakeRange(primaryString.length-1, primaryString.length);
NSDictionary *attributes = [primaryString attributesAtIndex:0 effectiveRange:&range];
NSMutableAttributedString *newString = [[NSMutableAttributedString alloc] initWithString:newString attributes:attributes];
NSMutableAttributedString *primaryStringMutable = [[NSMutableAttributedString alloc] initWithAttributedString:primaryString];

//change the string
[primaryStringMutable setAttributedString::newString];

primaryString = [NSAttributedString alloc] initWithAttributedString:primaryStringMutable];

答案 5 :(得分:0)

对于那些使用UIButton的人来说,这是一个基于Wes's的改进答案。

似乎更新按钮的标签最好这样做:

let newtext = "my new text"
myuibutton.setAttributedTitle(titlelabel.getTextWhileKeepingAttributes(string: newtext), for: .normal)

所以我最终得到了这个扩展名:

import UIKit

extension UILabel {
    func setTextWhileKeepingAttributes(string: String) {
        if let newAttributedText = self.attributedText {
            let mutableAttributedText = newAttributedText.mutableCopy()

            (mutableAttributedText as AnyObject).mutableString.setString(string)

            self.attributedText = mutableAttributedText as? NSAttributedString
        }
    }
    func getTextWhileKeepingAttributes(string: String) -> NSAttributedString {
        if let newAttributedText:NSAttributedString = self.attributedText {
            let mutableAttributedText = newAttributedText.mutableCopy()

            (mutableAttributedText as AnyObject).mutableString.setString(string)
            return mutableAttributedText as! NSAttributedString
        }
        else {
            // No attributes in this label, just create a new attributed string?
            let attributedstring = NSAttributedString.init(string: string)
            return attributedstring
        }
    }
}

答案 6 :(得分:0)

更改可变字符串的文本将不会执行作业,因为它只保留第一个字符的属性并将其应用于所有文本。这似乎是设计的,因为它是文档的一部分。

因此,如果要复制所有属性或更改字符串,则需要手动复制所有属性。然后,您可以创建MutableAttributedString并更改文本。然后将所有属性应用于新的MutableAttributedString。

我已经为Xamarin(在C#中)这样做了,但我认为你可以很容易地理解它并根据你的语言进行调整:

NSMutableAttributedString result = new 
NSMutableAttributedString(attrStr.Value.Replace(blackSquare, bullet));
// You cannot simply replace an AttributedString's string, because that will discard attributes. 
// Therefore, I will now copy all attributes manually to the new MutableAttributedString:
NSRange outRange = new NSRange(0, 0);
int attributeIndex = 0;
while (outRange.Location + outRange.Length < attrStr.Value.Length   // last attribute range reached
            && attributeIndex < attrStr.Value.Length)                    // or last character reached
{
       // Get all attributes for character at attributeIndex
       var attributes = attrStr.GetAttributes(attributeIndex, out outRange);
       if (attributes != null && attributes.Count > 0)
       {
               result.AddAttributes(attributes, outRange); // copy all found attributes to result
               attributeIndex = (int)(outRange.Location + outRange.Length); // continue with the next range
       }
       else
       {
               attributeIndex++; // no attribues at the current attributeIndex, so continue with the next char
       }

}
// all attributes are copied

答案 7 :(得分:0)

        let mutableAttributedString  = mySubTitleLabel.attributedText?.mutableCopy() as? NSMutableAttributedString
        if let attrStr = mutableAttributedString{
            attrStr.mutableString.setString("Inner space can be an example shown on the, third page of the tutorial.")
            mySubTitleLabel.attributedText = attrStr;
        }

我希望这段代码可以对您有所帮助,我已将标签的属性复制到mutableAttributedString,然后为其设置了字符串

答案 8 :(得分:0)

没有一个答案对我有用,但是这个答案;

extension UILabel{
func setTextWhileKeepingAttributes(_ string: String) {
        if let attributedText = self.attributedText {
            let attributedString = NSMutableAttributedString(string: string,
                                                             attributes: [NSAttributedString.Key.font: font])
            attributedText.enumerateAttribute(.font, in: NSRange(location: 0, length: attributedText.length)) { (value, range, stop) in
                let attributes = attributedText.attributes(at: range.location, effectiveRange: nil)
                attributedString.addAttributes(attributes, range: range)
            }
            self.attributedText = attributedString
        }
    }
}