如何使用Swift创建属性字符串?

dcb*_*nji 293 fonts nsattributedstring uilabel swift

我想制作一个简单的咖啡计算器.我需要以克为单位显示咖啡量.克的"g"符号需要附加到我用来显示金额的UILabel上.UILabel中的数字正在根据用户输入动态变化,但我需要在字符串末尾添加小写"g",其格式与更新数字不同.需要将"g"附加到数字上,以便随着数字大小和位置的变化,"g"随着数字"移动".我确信这个问题已经解决了,所以正确的方向链接会有所帮助,因为我已经搜索了我的小心脏.

我在文档中搜索了一个属性字符串,我甚至从应用程序商店下载了一个"Attributed String Creator",但结果代码是在Objective-C中,我使用的是Swift.什么是令人敬畏的,并且可能对其他开发人员学习这种语言有帮助,这是使用Swift中的属性字符串创建具有自定义属性的自定义字体的明显示例.这方面的文档非常令人困惑,因为没有非常明确的方法来解决这个问题.我的计划是创建属性字符串并将其添加到coffeeAmount字符串的末尾.

var coffeeAmount: String = calculatedCoffee + attributedText
Run Code Online (Sandbox Code Playgroud)

其中calculateCoffee是一个Int转换为字符串,"attributedText"是小写的"g",其中包含我想要创建的自定义字体.也许我会以错误的方式解决这个问题.任何帮助表示赞赏!

Sur*_*gch 926

在此输入图像描述

此答案已针对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
Run Code Online (Sandbox Code Playgroud)

文字颜色

let myAttribute = [ NSAttributedString.Key.foregroundColor: UIColor.blue ]
Run Code Online (Sandbox Code Playgroud)

背景颜色

let myAttribute = [ NSAttributedString.Key.backgroundColor: UIColor.yellow ]
Run Code Online (Sandbox Code Playgroud)

字形

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

在此输入图像描述

let myAttribute = [ NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue ]
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

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

let myAttribute = [ NSAttributedString.Key.shadow: myShadow ]
Run Code Online (Sandbox Code Playgroud)

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


属性

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

  • 键名:NSAttributedString.Key.font,值:aUIFont
  • 键名:NSAttributedString.Key.foregroundColor,值:aUIColor
  • 键名:NSAttributedString.Key.link,值:一个NSURLNSString

还有很多其他的.请参阅此链接了解更多信息 您甚至可以制作自己的自定义属性,例如:

  • 键名:NSAttributedString.Key.myName,值:某些类型.
    如果你做扩展:

    extension NSAttributedString.Key {
        static let myName = NSAttributedString.Key(rawValue: "myCustomAttributeKey")
    }
    
    Run Code Online (Sandbox Code Playgroud)

在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" ]
Run Code Online (Sandbox Code Playgroud)

请注意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
Run Code Online (Sandbox Code Playgroud)

归因于字符串

既然您了解了属性,那么您可以创建属性字符串.

初始化

有几种方法可以创建属性字符串.如果您只需要一个只读字符串就可以使用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)
Run Code Online (Sandbox Code Playgroud)

如果以后需要更改属性或字符串内容,则应使用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)
Run Code Online (Sandbox Code Playgroud)

更改归因字符串

举个例子,让我们在这篇文章的顶部创建一个属性字符串.

首先NSMutableAttributedString使用新的字体属性创建一个.

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

如果您正在使用,请将属性字符串设置为UITextView(或UILabel),如下所示:

textView.attributedText = myString
Run Code Online (Sandbox Code Playgroud)

不要使用textView.text.

结果如下:

在此输入图像描述

然后附加另一个没有设置任何属性的属性字符串.(请注意,即使我曾经letmyString上面声明,我仍然可以修改它,因为它是一个NSMutableAttributedString.这对我来说似乎很不顺便,如果将来发生这种变化,我也不会感到惊讶.发生这种情况时请留言.)

let attrString = NSAttributedString(string: " Attributed Strings")
myString.append(attrString)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

接下来我们只选择"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)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

最后,让我们添加背景颜色.对于多样性,让我们使用该addAttributes方法(注意s).我可以使用此方法一次添加多个属性,但我将再次添加一个.

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

在此输入图像描述

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

有关

进一步阅读

  • 请注意,您可以组合多种样式用于下划线,例如`NSUnderlineStyleAttributeName:NSUnderlineStyle.StyleSingle.rawValue | NSUnderlineStyle.PatternDot.rawValue` (4认同)
  • 你不能在NSAttributedString上使用appendAttributedString它必须在NSMutableAttributedString上,你能更新你的答案来反映这个吗? (3认同)
  • **1)**非常感谢您的回答.**2)**我建议您在答案的**开头**放置`textView.atrributedtText = myString`或`myLabel.attributedText = myString`.作为一个新手,我只是在做'myLabel.text`而且我认为我不需要通过*all*你的答案.**3)**这是否意味着你只能拥有`attributedText`或`text`拥有它们两者都没有意义?**4)**我建议您在答案中加入`lineSpacing`例如[this](http://stackoverflow.com/a/31642194/5175709),因为它非常有用.**5)**ачаардахин (3认同)
  • @Daniel,`addAttribute`是一个`NSMutableAttributedString`的方法.你是对的,你不能用`String`或`NSAttributedString`.(检查本帖子的**更改属性字符串**部分中的`myString`定义.我想我已经把你扔了,因为我还在帖子的第一部分使用`myString`作为变量名称`NSAttributedString`.) (2认同)

NRi*_*itH 108

Swift使用与NSMutableAttributedStringObj-C 相同的功能.您通过将计算的值作为字符串传递来实例化它:

var attributedString = NSMutableAttributedString(string:"\(calculatedCoffee)")
Run Code Online (Sandbox Code Playgroud)

现在创建属性g字符串(heh).注意: UIFont.systemFontOfSize(_)现在是一个可用的初始化程序,因此必须先将其解包,然后才能使用它:

var attrs = [NSFontAttributeName : UIFont.systemFontOfSize(19.0)!]
var gString = NSMutableAttributedString(string:"g", attributes:attrs)
Run Code Online (Sandbox Code Playgroud)

然后追加它:

attributedString.appendAttributedString(gString)
Run Code Online (Sandbox Code Playgroud)

然后,您可以设置UILabel以显示NSAttributedString,如下所示:

myLabel.attributedText = attributedString
Run Code Online (Sandbox Code Playgroud)

  • 如果您有属性字符串,则需要设置标签的attributedText属性而不是其text属性. (9认同)
  • 出于某种原因,我在使用NSAttributedString的行上收到了一个错误"调用中的额外参数".这只发生在我将UIFont.systemFontOfSize(18)切换到UIFont(名称:"Arial",大小:20)时.有任何想法吗? (2认同)

Ada*_*don 19

斯威夫特4:

let attributes = [NSAttributedStringKey.font: UIFont(name: "HelveticaNeue-Bold", size: 17)!, 
                  NSAttributedStringKey.foregroundColor: UIColor.white]
Run Code Online (Sandbox Code Playgroud)

  • 那就是问题,我的回答是大胆的标题"Swift 4",我强烈建议你更新到Swift 4 (4认同)

har*_*hoo 18

Xcode 6版本:

let attriString = NSAttributedString(string:"attriString", attributes:
[NSForegroundColorAttributeName: UIColor.lightGrayColor(), 
            NSFontAttributeName: AttriFont])
Run Code Online (Sandbox Code Playgroud)

Xcode 9.3版本:

let attriString = NSAttributedString(string:"attriString", attributes:
[NSAttributedStringKey.foregroundColor: UIColor.lightGray, 
            NSAttributedStringKey.font: AttriFont])
Run Code Online (Sandbox Code Playgroud)

Xcode 10,iOS 12,Swift 4:

let attriString = NSAttributedString(string:"attriString", attributes:
[NSAttributedString.Key.foregroundColor: UIColor.lightGray, 
            NSAttributedString.Key.font: AttriFont])
Run Code Online (Sandbox Code Playgroud)


Vin*_*shi 16

Swift:xcode 6.1

    let font:UIFont? = UIFont(name: "Arial", size: 12.0)

    let attrString = NSAttributedString(
        string: titleData,
        attributes: NSDictionary(
            object: font!,
            forKey: NSFontAttributeName))
Run Code Online (Sandbox Code Playgroud)


Men*_*dyK 15

我强烈建议使用库来归因字符串.它可以让你容易,例如,一个字符串有四种不同的颜色和四种不同的字体. 这是我的最爱.它被称为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
Run Code Online (Sandbox Code Playgroud)

finalString 会显示为

显示为图像


Gur*_*ngh 11

斯威夫特 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
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明


And*_*rey 9

在测试版6中运行良好

let attrString = NSAttributedString(
    string: "title-title-title",
    attributes: NSDictionary(
       object: NSFont(name: "Arial", size: 12.0), 
       forKey: NSFontAttributeName))
Run Code Online (Sandbox Code Playgroud)


小智 8

在iOS上使用Attributed Strings的最佳方法是在界面构建器中使用内置的Attributed Text编辑器,并避免在源文件中使用不必要的硬编码NSAtrributedStringKeys.

您可以稍后使用此扩展名在运行时动态替换placehoderls:

extension NSAttributedString {
    func replacing(placeholder:String, with valueString:String) -> NSAttributedString {

        if let range = self.string.range(of:placeholder) {
            let nsRange = NSRange(range,in:valueString)
            let mutableText = NSMutableAttributedString(attributedString: self)
            mutableText.replaceCharacters(in: nsRange, with: valueString)
            return mutableText as NSAttributedString
        }
        return self
    }
}
Run Code Online (Sandbox Code Playgroud)

添加一个故事板标签,其属性文本如下所示.

在此输入图像描述

然后,您只需在每次需要时更新值,如下所示:

label.attributedText = initalAttributedString.replacing(placeholder: "<price>", with: newValue)
Run Code Online (Sandbox Code Playgroud)

确保将原始值保存到initalAttributedString中.

通过阅读本文,您可以更好地理解这种方法:https: //medium.com/mobile-appetite/text-attributes-on-ios-the-effortless-approach-ff086588173e


A.G*_*A.G 7

Swift 2.0

这是一个示例:

let newsString: NSMutableAttributedString = NSMutableAttributedString(string: "Tap here to read the latest Football News.")
newsString.addAttributes([NSUnderlineStyleAttributeName: NSUnderlineStyle.StyleDouble.rawValue], range: NSMakeRange(4, 4))
sampleLabel.attributedText = newsString.copy() as? NSAttributedString
Run Code Online (Sandbox Code Playgroud)

要么

let stringAttributes = [
    NSFontAttributeName : UIFont(name: "Helvetica Neue", size: 17.0)!,
    NSUnderlineStyleAttributeName : 1,
    NSForegroundColorAttributeName : UIColor.orangeColor(),
    NSTextEffectAttributeName : NSTextEffectLetterpressStyle,
    NSStrokeWidthAttributeName : 2.0]
let atrributedString = NSAttributedString(string: "Sample String: Attributed", attributes: stringAttributes)
sampleLabel.attributedText = atrributedString
Run Code Online (Sandbox Code Playgroud)


And*_*res 7

我创建了一个可以解决您问题的在线工具!您可以编写字符串并以图形方式应用样式,该工具为您提供objective-c和swift代码以生成该字符串.

也是开源的,所以随意扩展它并发送PR.

变压器工具

Github上

在此输入图像描述


Vas*_*huk 7

细节

  • Swift 5.2,Xcode 11.4 (11E146)

解决方案

protocol AttributedStringComponent {
    var text: String { get }
    func getAttributes() -> [NSAttributedString.Key: Any]?
}

// MARK: String extensions

extension String: AttributedStringComponent {
    var text: String { self }
    func getAttributes() -> [NSAttributedString.Key: Any]? { return nil }
}

extension String {
    func toAttributed(with attributes: [NSAttributedString.Key: Any]?) -> NSAttributedString {
        .init(string: self, attributes: attributes)
    }
}

// MARK: NSAttributedString extensions

extension NSAttributedString: AttributedStringComponent {
    var text: String { string }

    func getAttributes() -> [Key: Any]? {
        if string.isEmpty { return nil }
        var range = NSRange(location: 0, length: string.count)
        return attributes(at: 0, effectiveRange: &range)
    }
}

extension NSAttributedString {

    convenience init?(from attributedStringComponents: [AttributedStringComponent],
                      defaultAttributes: [NSAttributedString.Key: Any],
                      joinedSeparator: String = " ") {
        switch attributedStringComponents.count {
        case 0: return nil
        default:
            var joinedString = ""
            typealias SttributedStringComponentDescriptor = ([NSAttributedString.Key: Any], NSRange)
            let sttributedStringComponents = attributedStringComponents.enumerated().flatMap { (index, component) -> [SttributedStringComponentDescriptor] in
                var components = [SttributedStringComponentDescriptor]()
                if index != 0 {
                    components.append((defaultAttributes,
                                       NSRange(location: joinedString.count, length: joinedSeparator.count)))
                    joinedString += joinedSeparator
                }
                components.append((component.getAttributes() ?? defaultAttributes,
                                   NSRange(location: joinedString.count, length: component.text.count)))
                joinedString += component.text
                return components
            }

            let attributedString = NSMutableAttributedString(string: joinedString)
            sttributedStringComponents.forEach { attributedString.addAttributes($0, range: $1) }
            self.init(attributedString: attributedString)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法

let defaultAttributes = [
    .font: UIFont.systemFont(ofSize: 16, weight: .regular),
    .foregroundColor: UIColor.blue
] as [NSAttributedString.Key : Any]

let marketingAttributes = [
    .font: UIFont.systemFont(ofSize: 20.0, weight: .bold),
    .foregroundColor: UIColor.black
] as [NSAttributedString.Key : Any]

let attributedStringComponents = [
    "pay for",
    NSAttributedString(string: "one",
                       attributes: marketingAttributes),
    "and get",
    "three!\n".toAttributed(with: marketingAttributes),
    "Only today!".toAttributed(with: [
        .font: UIFont.systemFont(ofSize: 16.0, weight: .bold),
        .foregroundColor: UIColor.red
    ])
] as [AttributedStringComponent]
let attributedText = NSAttributedString(from: attributedStringComponents, defaultAttributes: defaultAttributes)
Run Code Online (Sandbox Code Playgroud)

完整示例

不要忘记在此处粘贴解决方案代码

import UIKit

class ViewController: UIViewController {

    private weak var label: UILabel!
    override func viewDidLoad() {
        super.viewDidLoad()
        let label = UILabel(frame: .init(x: 40, y: 40, width: 300, height: 80))
        label.numberOfLines = 2
        view.addSubview(label)
        self.label = label

        let defaultAttributes = [
            .font: UIFont.systemFont(ofSize: 16, weight: .regular),
            .foregroundColor: UIColor.blue
        ] as [NSAttributedString.Key : Any]

        let marketingAttributes = [
            .font: UIFont.systemFont(ofSize: 20.0, weight: .bold),
            .foregroundColor: UIColor.black
        ] as [NSAttributedString.Key : Any]

        let attributedStringComponents = [
            "pay for",
            NSAttributedString(string: "one",
                               attributes: marketingAttributes),
            "and get",
            "three!\n".toAttributed(with: marketingAttributes),
            "Only today!".toAttributed(with: [
                .font: UIFont.systemFont(ofSize: 16.0, weight: .bold),
                .foregroundColor: UIColor.red
            ])
        ] as [AttributedStringComponent]
        label.attributedText = NSAttributedString(from: attributedStringComponents, defaultAttributes: defaultAttributes)
        label.textAlignment = .center
    }
}
Run Code Online (Sandbox Code Playgroud)

结果

在此处输入图片说明


mid*_*n p 6

Swift 5 及以上

   let attributedString = NSAttributedString(string:"targetString",
                                   attributes:[NSAttributedString.Key.foregroundColor: UIColor.lightGray,
                                               NSAttributedString.Key.font: UIFont(name: "Arial", size: 18.0) as Any])
Run Code Online (Sandbox Code Playgroud)


Pri*_*tel 6

斯威夫特 3,4,5

使用以下代码设置文本颜色、字体、背景颜色和下划线/下划线颜色

    let text = "swift is language"
    let attributes = [NSAttributedString.Key.foregroundColor: UIColor.red, NSAttributedString.Key.backgroundColor: UIColor.blue,NSAttributedString.Key.font: UIFont.systemFont(ofSize: 25.0),NSAttributedString.Key.underlineColor: UIColor.white,NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue] as [NSAttributedString.Key : Any]
        
    let textAttribute = NSAttributedString(string: text, attributes: attributes)
    swiftLabel1.attributedText = textAttribute
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


Yog*_*del 5

func decorateText(sub:String, des:String)->NSAttributedString{
    let textAttributesOne = [NSAttributedStringKey.foregroundColor: UIColor.darkText, NSAttributedStringKey.font: UIFont(name: "PTSans-Bold", size: 17.0)!]
    let textAttributesTwo = [NSAttributedStringKey.foregroundColor: UIColor.black, NSAttributedStringKey.font: UIFont(name: "PTSans-Regular", size: 14.0)!]

    let textPartOne = NSMutableAttributedString(string: sub, attributes: textAttributesOne)
    let textPartTwo = NSMutableAttributedString(string: des, attributes: textAttributesTwo)

    let textCombination = NSMutableAttributedString()
    textCombination.append(textPartOne)
    textCombination.append(textPartTwo)
    return textCombination
}
Run Code Online (Sandbox Code Playgroud)

//执行

cell.lblFrom.attributedText = decorateText(sub: sender!, des: " - \(convertDateFormatShort3(myDateString: datetime!))")
Run Code Online (Sandbox Code Playgroud)