I am trying to make a simple Coffee Calculator. I need to display the amount of coffee in grams. The "g" symbol for grams needs to be attached to my UILabel that I am using to display the amount. The numbers in the UILabel are changing dynamically with user input just fine, but I need to add a lower case "g" on the end of the string that is formatted differently from the updating numbers. The "g" needs to be attached to the numbers so that as the number size and position changes, the "g" "moves" with the numbers. I'm sure this problem has been solved before so a link in the right direction would be helpful as I've googled my little heart out.

I've searched through the documentation for an attributed string and I even downloded an "Attributed String Creator" from the app store, but the resulting code is in Objective-C and I am using Swift. What would be awesome, and probably helpful to other developers learning this language, is a clear example of creating a custom font with custom attributes using an attributed string in Swift. The documentation for this is very confusing as there is not a very clear path on how to do so. My plan is to create the attributed string and add it to the end of my coffeeAmount string.

var coffeeAmount: String = calculatedCoffee + attributedText

其中calculatedCoffee是一个Int转换为字符串和“attributedText”是小写的“g”与自定义字体,我试图创建。也许我做错了。任何帮助都是感激的!


当前回答

我强烈建议使用带属性字符串的库。当你想要,例如,一个字符串有四种不同的颜色和四种不同的字体时,它使它变得更容易。这是我最喜欢的。它被称为SwiftyAttributes

如果你想用SwiftyAttributes创建一个有四种不同颜色和不同字体的字符串:

let magenta = "Hello ".withAttributes([
    .textColor(.magenta),
    .font(.systemFont(ofSize: 15.0))
    ])
let cyan = "Sir ".withAttributes([
    .textColor(.cyan),
    .font(.boldSystemFont(ofSize: 15.0))
    ])
let green = "Lancelot".withAttributes([
    .textColor(.green),
    .font(.italicSystemFont(ofSize: 15.0))

    ])
let blue = "!".withAttributes([
    .textColor(.blue),
    .font(.preferredFont(forTextStyle: UIFontTextStyle.headline))

    ])
let finalString = magenta + cyan + green + blue

finalString将显示为

其他回答

 let attrString = NSAttributedString (
            string: "title-title-title",
            attributes: [NSAttributedStringKey.foregroundColor: UIColor.black])

我创建了一个在线工具来解决你的问题!你可以编写字符串并以图形化的方式应用样式,该工具会给你objective-c和swift代码来生成字符串。

Also是开源的,所以请随意扩展它并发送pr。

变压器的工具

Github

这个答案已经在Swift 4.2中更新了。

快速参考

创建和设置带属性字符串的一般形式如下所示。你可以在下面找到其他常见的选项。

// create attributed string
let myString = "Swift Attributed String"
let myAttribute = [ NSAttributedString.Key.foregroundColor: UIColor.blue ]
let myAttrString = NSAttributedString(string: myString, attributes: myAttribute) 

// set attributed text on a UILabel
myLabel.attributedText = myAttrString

let myAttribute = [ NSAttributedString.Key.foregroundColor: UIColor.blue ]

let myAttribute = [ NSAttributedString.Key.backgroundColor: UIColor.yellow ]

let myAttribute = [ NSAttributedString.Key.font: UIFont(name: "Chalkduster", size: 18.0)! ]

let myAttribute = [ NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue ]

let myShadow = NSShadow()
myShadow.shadowBlurRadius = 3
myShadow.shadowOffset = CGSize(width: 3, height: 3)
myShadow.shadowColor = UIColor.gray

let myAttribute = [ NSAttributedString.Key.shadow: myShadow ]

这篇文章的其余部分将为感兴趣的人提供更多细节。


属性

字符串属性只是一个[NSAttributedString]形式的字典。键:Any],其中NSAttributedString。Key是属性的键名,Any是某个Type的值。该值可以是字体、颜色、整数或其他内容。Swift中有许多已经预先定义好的标准属性。例如:

键名:NSAttributedString.Key。字体,值:一个UIFont 键名:NSAttributedString.Key。foregroundColor, value:一个UIColor 键名:NSAttributedString.Key。link,值:NSURL或NSString

还有很多其他的。更多信息请参见此链接。你甚至可以创建自己的自定义属性,比如:

键名:NSAttributedString.Key。myName,值:some类型。 如果你进行延期: NSAttributedString延伸。关键{ static let myName = NSAttributedString。键(rawValue:“myCustomAttributeKey”) }

在Swift中创建属性

您可以像声明任何其他字典一样声明属性。

// single attributes declared one at a time
let singleAttribute1 = [ NSAttributedString.Key.foregroundColor: UIColor.green ]
let singleAttribute2 = [ NSAttributedString.Key.backgroundColor: UIColor.yellow ]
let singleAttribute3 = [ NSAttributedString.Key.underlineStyle: NSUnderlineStyle.double.rawValue ]

// multiple attributes declared at once
let multipleAttributes: [NSAttributedString.Key : Any] = [
    NSAttributedString.Key.foregroundColor: UIColor.green,
    NSAttributedString.Key.backgroundColor: UIColor.yellow,
    NSAttributedString.Key.underlineStyle: NSUnderlineStyle.double.rawValue ]

// custom attribute
let customAttribute = [ NSAttributedString.Key.myName: "Some value" ]

注意下划线样式值所需要的rawValue。

因为属性只是字典,您也可以通过创建一个空字典,然后向其添加键值对来创建它们。如果该值将包含多个类型,则必须使用Any作为类型。下面是上面的multipleAttributes示例,以这种方式重新创建:

var multipleAttributes = [NSAttributedString.Key : Any]()
multipleAttributes[NSAttributedString.Key.foregroundColor] = UIColor.green
multipleAttributes[NSAttributedString.Key.backgroundColor] = UIColor.yellow
multipleAttributes[NSAttributedString.Key.underlineStyle] = NSUnderlineStyle.double.rawValue

由于字符串

了解了属性之后,就可以创建带属性的字符串了。

初始化

有几种方法可以创建带属性的字符串。如果你只需要一个只读字符串,你可以使用NSAttributedString。这里有一些初始化它的方法:

// Initialize with a string only
let attrString1 = NSAttributedString(string: "Hello.")

// Initialize with a string and inline attribute(s)
let attrString2 = NSAttributedString(string: "Hello.", attributes: [NSAttributedString.Key.myName: "A value"])

// Initialize with a string and separately declared attribute(s)
let myAttributes1 = [ NSAttributedString.Key.foregroundColor: UIColor.green ]
let attrString3 = NSAttributedString(string: "Hello.", attributes: myAttributes1)

如果你以后需要改变属性或字符串内容,你应该使用NSMutableAttributedString。声明非常相似:

// Create a blank attributed string
let mutableAttrString1 = NSMutableAttributedString()

// Initialize with a string only
let mutableAttrString2 = NSMutableAttributedString(string: "Hello.")

// Initialize with a string and inline attribute(s)
let mutableAttrString3 = NSMutableAttributedString(string: "Hello.", attributes: [NSAttributedString.Key.myName: "A value"])

// Initialize with a string and separately declared attribute(s)
let myAttributes2 = [ NSAttributedString.Key.foregroundColor: UIColor.green ]
let mutableAttrString4 = NSMutableAttributedString(string: "Hello.", attributes: myAttributes2)

更改带属性字符串

例如,让我们在这篇文章的顶部创建带属性的字符串。

首先创建一个带有新字体属性的NSMutableAttributedString。

let myAttribute = [ NSAttributedString.Key.font: UIFont(name: "Chalkduster", size: 18.0)! ]
let myString = NSMutableAttributedString(string: "Swift", attributes: myAttribute )

如果你正在处理,将带属性的字符串设置为UITextView(或UILabel),如下所示:

textView.attributedText = myString

你不用textview。text。

结果如下:

然后附加另一个没有设置任何属性的带属性字符串。(注意,即使我在上面使用let声明myString,我仍然可以修改它,因为它是一个NSMutableAttributedString。对我来说,这似乎不太像斯威夫特,如果将来这种情况发生变化,我也不会感到惊讶。如果发生这种情况,请给我留言。)

let attrString = NSAttributedString(string: " Attributed Strings")
myString.append(attrString)

接下来,我们只选择“Strings”单词,它从索引17开始,长度为7。注意,这是一个NSRange而不是Swift Range。(有关Ranges的更多信息,请参阅这个答案。)addAttribute方法允许我们将属性键名放在第一个位置,属性值放在第二个位置,范围放在第三个位置。

var myRange = NSRange(location: 17, length: 7) // range starting at location 17 with a lenth of 7: "Strings"
myString.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.red, range: myRange)

最后,让我们添加一个背景色。为了多样化,让我们使用addAttributes方法(注意s)。我可以用这个方法一次添加多个属性,但我将再次添加一个。

myRange = NSRange(location: 3, length: 17)
let anotherAttribute = [ NSAttributedString.Key.backgroundColor: UIColor.yellow ]
myString.addAttributes(anotherAttribute, range: myRange)

注意,属性在某些地方是重叠的。添加属性不会覆盖已经存在的属性。

相关的

如何改变一个NSMutableAttributedString的文本,但保持属性

进一步的阅读

如何从一个点击位置检索属性 带属性字符串编程指南(非常有用,但不幸的是仅在Objective-C中)

斯威夫特5

let attrStri = NSMutableAttributedString.init(string:"This is red")
let nsRange = NSString(string: "This is red")
        .range(of: "red", options: String.CompareOptions.caseInsensitive)
attrStri.addAttributes([
    NSAttributedString.Key.foregroundColor : UIColor.red,
    NSAttributedString.Key.font: UIFont.init(name: "PTSans-Regular", size: 15.0) as Any
], range: nsRange)
self.label.attributedText = attrStri

斯威夫特有一个非常甜蜜的方式来做到这一点,真的不需要任何工作。只需提供应该匹配的模式以及应用于它的属性。它们在很多方面都很有用,去看看吧。

``` Swift
let defaultGenreText = NSAttributedString(string: "Select Genre - Required")
let redGenreText = defaultGenreText.applying(attributes: [NSAttributedString.Key.foregroundColor : UIColor.red], toRangesMatching: "Required")
``

如果你有多个地方,这将被应用,你只希望它发生在特定的实例,那么这个方法将不起作用。

你可以一步完成,只是分开时更容易阅读。