ios 在不修改其他属性的情况下替换 NSAttributedString 中的整个文本字符串

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30267591/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 05:59:17  来源:igfitidea点击:

replace entire text string in NSAttributedString without modifying other attributes

iosobjective-cnsattributedstring

提问by Chirag Jain

I have a reference to NSAttributedStringand i want to change the text of the attributed string.

我有一个参考NSAttributedString,我想更改属性字符串的文本。

I guess i have to created a new NSAttributedStringand update the reference with this new string. However when i do this i lose the attributed of previous string.

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

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

I have reference to old attributed string in self.attributedText. How can i retain the previous attributed in the new string?

我在self.attributedText. 如何在新字符串中保留以前的属性?

回答by Artal

You can use NSMutableAttributedString and just update the string, the attributes won't change. Example:

您可以使用 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"];

回答by Suragch

Swift

迅速

Change the text while keeping the attributes:

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

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)

The results for mutableAttributedStringare

结果mutableAttributedString

  • enter image description here
  • enter image description here
  • enter image description here
  • enter image description here

Notes

笔记

Any sub-ranges of attributes beyond index 0 are discarded. For example, if I add another attribute to the last word of the original string, it is lost after I change the string:

任何超出索引 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)

Results:

结果:

  • enter image description here
  • enter image description here
  • enter image description here
  • enter image description here

From this we can see that the new string gets whatever the attributes are at index 0 of the original string. Indeed, if we adjust the range to be

由此我们可以看到,新字符串获得了原始字符串索引 0 处的任何属性。事实上,如果我们将范围调整为

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

we get

我们得到

  • enter image description here
  • enter image description here
  • enter image description here
  • enter image description here

See also

也可以看看

回答by Wes

I made a little extension to make this really easy:

我做了一些扩展,使这真的很容易:

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

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

回答by Syed Zahid Shah

        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;
        }

I hope this code may help you, i have copied the attribute of the label to a mutableAttributedString and then set the string for it

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

回答by Darius Miliauskas

This is the way using Objective-C (tested on iOS 9)

这是使用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];

Check for the most important references: attributesAtIndex:effectiveRange:and setAttributedString:.

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

回答by DuckDucking

Darius answer is almost there. It contains a minor error. The correct is:

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

This is the way using Objective-C (tested on iOS 10)

这是使用 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];

回答by Jonny

For those of you working with UIButtons, here is an improved answer based on Wes's.

对于那些使用 UIButtons 的人,这里有一个基于Wes's的改进答案。

It seemed that updating a label of a button had better be done this way:

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

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

So I ended up with this extension:

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

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
        }
    }
}

回答by Viktor

Changing the text of a mutable string will not do the jobs, since it will only keep the attributes of the first character and apply this to all of the text. Which seems to be by design, since it is part of the documentation.

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

So if you want to copy all attributes or change the string, you need to copy all attributes manually. Then you can create a MutableAttributedString and change the text. Afterwards you apply all the attributes to the new MutableAttributedString.

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

I have done it this way for Xamarin (in C#), but I think you can easily understand it and adapt it for your language:

我已经为 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

回答by seymatanoglu

None of the answers worked for me, but this one;

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

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
        }
    }
}