在不修改其他属性的情况下替换 NSAttributedString 中的整个文本字符串
replace entire text string in NSAttributedString without modifying other attributes
我有对 NSAttributedString
的引用,我想更改属性字符串的文本。
我想我必须创建一个新的 NSAttributedString
并用这个新字符串更新引用。但是,当我这样做时,我丢失了先前字符串的属性。
NSAttributedString *newString = [[NSAttributedString alloc] initWithString:text];
[self setAttributedText:newString];
我参考了 self.attributedText
中的旧属性字符串。如何在新字符串中保留之前的属性?
您可以使用 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"];
Swift
在保留属性的同时更改文本:
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
的结果是
备注
超过索引 0 的任何 sub-ranges 属性都将被丢弃。例如,如果我在原始字符串的最后一个单词上添加另一个属性,则在我更改字符串后它会丢失:
// 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)
结果:
由此我们可以看出,新字符串获取了原始字符串索引 0 处的所有属性。实际上,如果我们将范围调整为
let myRange = NSRange(location: 0, length: 1)
我们得到
另见
- my main answer about Swift attributed strings
这是使用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: and setAttributedString:。
Darius 的答案就快出来了。它包含一个小错误。正确的是:
这是使用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];
我做了一些扩展,使这变得非常简单:
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
对于那些使用 UIButtons 的人,这是一个基于 的改进答案。
看来更新按钮的标签最好这样:
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
}
}
}
更改可变字符串的文本将不起作用,因为它只会保留第一个字符的属性并将其应用于所有文本。这似乎是设计使然,因为它是文档的一部分。
所以如果你想复制所有的属性或者改变字符串,你需要手动复制所有的属性。然后您可以创建一个 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
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 中,然后为其设置字符串
None 个答案对我有用,但是这个;
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
}
}
}
我有对 NSAttributedString
的引用,我想更改属性字符串的文本。
我想我必须创建一个新的 NSAttributedString
并用这个新字符串更新引用。但是,当我这样做时,我丢失了先前字符串的属性。
NSAttributedString *newString = [[NSAttributedString alloc] initWithString:text];
[self setAttributedText:newString];
我参考了 self.attributedText
中的旧属性字符串。如何在新字符串中保留之前的属性?
您可以使用 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"];
Swift
在保留属性的同时更改文本:
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
的结果是
备注
超过索引 0 的任何 sub-ranges 属性都将被丢弃。例如,如果我在原始字符串的最后一个单词上添加另一个属性,则在我更改字符串后它会丢失:
// 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)
结果:
由此我们可以看出,新字符串获取了原始字符串索引 0 处的所有属性。实际上,如果我们将范围调整为
let myRange = NSRange(location: 0, length: 1)
我们得到
另见
- my main answer about Swift attributed strings
这是使用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: and setAttributedString:。
Darius 的答案就快出来了。它包含一个小错误。正确的是:
这是使用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];
我做了一些扩展,使这变得非常简单:
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
对于那些使用 UIButtons 的人,这是一个基于
看来更新按钮的标签最好这样:
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
}
}
}
更改可变字符串的文本将不起作用,因为它只会保留第一个字符的属性并将其应用于所有文本。这似乎是设计使然,因为它是文档的一部分。
所以如果你想复制所有的属性或者改变字符串,你需要手动复制所有的属性。然后您可以创建一个 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
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 中,然后为其设置字符串
None 个答案对我有用,但是这个;
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
}
}
}