web-dev-qa-db-fra.com

Comment créer une chaîne attribuée avec Swift?

J'essaie de faire une simple calculatrice de café. Je dois afficher la quantité de café en grammes. Le symbole "g" pour les grammes doit être attaché à mon UILabel que j'utilise pour afficher le montant. Les numéros dans UILabel changent dynamiquement avec la saisie de l'utilisateur, mais je dois ajouter un "g" en minuscule à la fin de la chaîne qui est formatée différemment des nombres mis à jour. Le "g" doit être attaché aux nombres afin que, à mesure que la taille et la position du nombre changent, le "g" "se déplace" avec les nombres. Je suis sûr que ce problème a déjà été résolu, donc un lien dans la bonne direction serait utile, car j'ai cherché mon petit coeur sur Google.

J'ai cherché dans la documentation une chaîne attribuée et j'ai même téléchargé un "Créateur de chaîne attribuée" depuis l'App Store, mais le code obtenu est en Objective-C et j'utilise Swift. Ce qui serait génial, et probablement utile aux autres développeurs apprenant ce langage, est un exemple clair de création d'une police personnalisée avec des attributs personnalisés à l'aide d'une chaîne attribuée à Swift. La documentation à ce sujet est très déroutante car il n’ya pas de chemin clair à suivre. Mon plan est de créer la chaîne attribuée et de l'ajouter à la fin de ma chaîne coffeeAmount.

var coffeeAmount: String = calculatedCoffee + attributedText

Où calculeCoffee est un Int converti en chaîne et "attributText" est le minuscule "g" avec la police personnalisée que je tente de créer. Peut-être que je m'y prends mal. Toute aide est appréciée!

260
dcbenji

enter image description here

Cette réponse a été mise à jour pour Swift 4.2.

Référence rapide

La forme générale pour créer et définir une chaîne attribuée est comme ceci. Vous pouvez trouver d'autres options communes ci-dessous.

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

Text Color

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

Background Color

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

Font

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

enter image description here

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

enter image description here

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

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

Le reste de cet article donne plus de détails pour ceux qui sont intéressés.


Les attributs

Les attributs de chaîne ne sont qu'un dictionnaire sous la forme de [NSAttributedString.Key: Any], où NSAttributedString.Key est le nom de clé de l'attribut et Any est la valeur d'un type. La valeur peut être une police, une couleur, un entier ou autre chose. De nombreux attributs standard dans Swift ont déjà été prédéfinis. Par exemple:

  • nom de la clé: NSAttributedString.Key.font, valeur: une UIFont
  • nom de la clé: NSAttributedString.Key.foregroundColor, valeur: une UIColor
  • nom de la clé: NSAttributedString.Key.link, valeur: une NSURL ou NSString

Il y en a beaucoup d'autres. Voir ce lien pour plus d'informations. Vous pouvez même créer vos propres attributs personnalisés, tels que:

  • nom de clé: NSAttributedString.Key.myName, valeur: un type.
    si vous faites un extension :

    extension NSAttributedString.Key {
        static let myName = NSAttributedString.Key(rawValue: "myCustomAttributeKey")
    }
    

Créer des attributs dans Swift

Vous pouvez déclarer des attributs comme si vous déclariez un autre dictionnaire.

// 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" ]

Notez la rawValue qui était nécessaire pour la valeur du style souligné.

Comme les attributs ne sont que des dictionnaires, vous pouvez également les créer en créant un dictionnaire vide, puis en y ajoutant des paires clé-valeur. Si la valeur contient plusieurs types, vous devez alors utiliser Any comme type. Voici l'exemple multipleAttributes du dessus, recréé de cette façon:

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

Chaînes Attribuées

Maintenant que vous comprenez les attributs, vous pouvez créer des chaînes attribuées.

Initialisation

Il existe plusieurs façons de créer des chaînes attribuées. Si vous avez juste besoin d'une chaîne en lecture seule, vous pouvez utiliser NSAttributedString. Voici quelques façons de l'initialiser:

// 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)

Si vous devez modifier les attributs ou le contenu de la chaîne ultérieurement, vous devez utiliser NSMutableAttributedString. Les déclarations sont très similaires:

// 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)

Changer une chaîne attribuée

Par exemple, créons la chaîne attribuée en haut de cet article.

Créez d’abord une NSMutableAttributedString avec un nouvel attribut de police.

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

Si vous continuez, définissez la chaîne attribuée sur une UITextView (ou UILabel) comme ceci:

textView.attributedText = myString

Vous ne pas utiliser textView.text.

Voici le résultat: 

enter image description here

Ajoutez ensuite une autre chaîne attribuée sans attribut. (Notez que même si j’ai utilisé let pour déclarer myString ci-dessus, je peux toujours le modifier car c’est un NSMutableAttributedString. Cela me semble plutôt inhabituel et je ne serais pas surpris que cela change à l’avenir. Laissez-moi un commentaire. arrive.)

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

enter image description here

Ensuite, nous allons simplement sélectionner le mot "Strings", qui commence à l’index 17 et a une longueur de 7. Notez qu'il s'agit d'une NSRange et non d'une Swift Range. (Voir cette réponse pour en savoir plus sur les plages.) La méthode addAttribute nous permet de placer le nom de la clé d'attribut au premier emplacement, la valeur de l'attribut au deuxième emplacement et la plage au troisième.

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)

enter image description here

Enfin, ajoutons une couleur de fond. Pour varier, utilisons la méthode addAttributes (notez la s). Je pourrais ajouter plusieurs attributs à la fois avec cette méthode, mais je vais simplement en ajouter un à nouveau.

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

enter image description here

Notez que les attributs se chevauchent à certains endroits. L'ajout d'un attribut n'écrase pas un attribut déjà présent.

En relation

Lectures complémentaires

849
Suragch

Swift utilise la même NSMutableAttributedString qu'Obj-C. Vous l'instanciez en transmettant la valeur calculée sous forme de chaîne:

var attributedString = NSMutableAttributedString(string:"\(calculatedCoffee)")

Créez maintenant la chaîne g attribuée (heh). Remarque: UIFont.systemFontOfSize(_) est maintenant un initialiseur disponible. Il doit donc être déballé avant de pouvoir être utilisé:

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

Et puis l'ajouter:

attributedString.appendAttributedString(gString)

Vous pouvez ensuite paramétrer UILabel pour afficher NSAttributedString comme ceci:

myLabel.attributedText = attributedString
101
NRitH

Swift 4:

let attributes = [NSAttributedStringKey.font: UIFont(name: "HelveticaNeue-Bold", size: 17)!, 
                  NSAttributedStringKey.foregroundColor: UIColor.white]
19
Adam Bardon

Version Xcode 6 :

let attriString = NSAttributedString(string:"attriString", attributes:
[NSForegroundColorAttributeName: UIColor.lightGrayColor(), 
            NSFontAttributeName: AttriFont])

Version Xcode 9.3 :

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

Xcode 10, iOS 12, Swift 4 :

let attriString = NSAttributedString(string:"attriString", attributes:
[NSAttributedString.Key.foregroundColor: UIColor.lightGray, 
            NSAttributedString.Key.font: AttriFont])
17
harthoo

Swift: xcode 6.1

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

    let attrString = NSAttributedString(
        string: titleData,
        attributes: NSDictionary(
            object: font!,
            forKey: NSFontAttributeName))
16
Vinod Joshi

Fonctionne bien en beta 6

let attrString = NSAttributedString(
    string: "title-title-title",
    attributes: NSDictionary(
       object: NSFont(name: "Arial", size: 12.0), 
       forKey: NSFontAttributeName))
9
Andrey

Swift 2.0

Voici un échantillon:

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

OR

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
7
A.G

La meilleure façon d'approcher les chaînes attribuées sur iOS consiste à utiliser l'éditeur de texte attribué intégré dans le générateur d'interface et à éviter le codage en dur inutile de NSAtrributedStringKeys dans vos fichiers source.

Vous pouvez ultérieurement remplacer dynamiquement des placehoderls au moment de l'exécution en utilisant cette extension:

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

Ajoutez une étiquette de storyboard avec un texte attribué ressemblant à ceci. 

 enter image description here

Ensuite, vous mettez simplement à jour la valeur chaque fois que vous avez besoin de ceci:

label.attributedText = initalAttributedString.replacing(placeholder: "<price>", with: newValue)

Veillez à enregistrer dans initalAttributedString la valeur d'origine. 

Vous pouvez mieux comprendre cette approche en lisant cet article: https://medium.com/mobile-appetite/text-attributes-on-ios-the-effortless-approach-ff086588173e

6
Efraim

J'ai créé un outil en ligne qui va résoudre votre problème! Vous pouvez écrire votre chaîne et appliquer des styles de manière graphique. L'outil vous fournit le code objectif-c et Swift pour générer cette chaîne.

Aussi est open source alors n'hésitez pas à l'étendre et envoyer des PR.

Outil de transformation

Github

 enter image description here

6
Andres

Swift 4

let attributes = [NSAttributedStringKey.font : UIFont(name: CustomFont.NAME_REGULAR.rawValue, size: CustomFontSize.SURVEY_FORM_LABEL_SIZE.rawValue)!]

let attributedString : NSAttributedString = NSAttributedString(string: messageString, attributes: attributes)

Vous devez supprimer la valeur brute dans Swift 4

4
Neha

Pour moi, les solutions ci-dessus ne fonctionnaient pas pour définir une couleur ou une propriété spécifique. 

Cela a fonctionné: 

let attributes = [
    NSFontAttributeName : UIFont(name: "Helvetica Neue", size: 12.0)!,
    NSUnderlineStyleAttributeName : 1,
    NSForegroundColorAttributeName : UIColor.darkGrayColor(),
    NSTextEffectAttributeName : NSTextEffectLetterpressStyle,
    NSStrokeWidthAttributeName : 3.0]

var atriString = NSAttributedString(string: "My Attributed String", attributes: attributes)
4
swennemen
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
}

//La mise en oeuvre

cell.lblFrom.attributedText = decorateText(sub: sender!, des: " - \(convertDateFormatShort3(myDateString: datetime!))")
4
Yogesh Tandel

Swift 2.1 - Xcode 7

let labelFont = UIFont(name: "HelveticaNeue-Bold", size: 18)
let attributes :[String:AnyObject] = [NSFontAttributeName : labelFont!]
let attrString = NSAttributedString(string:"foo", attributes: attributes)
myLabel.attributedText = attrString
3
 let attrString = NSAttributedString (
            string: "title-title-title",
            attributes: [NSAttributedStringKey.foregroundColor: UIColor.black])
2
Eugene Braginets

Les attributs peuvent être réglés directement dans Swift 3 ...

    let attributes = NSAttributedString(string: "String", attributes: [NSFontAttributeName : UIFont(name: "AvenirNext-Medium", size: 30)!,
         NSForegroundColorAttributeName : UIColor .white,
         NSTextEffectAttributeName : NSTextEffectLetterpressStyle])

Puis utilisez la variable dans n'importe quelle classe avec des attributs

2
Sebastian
extension UILabel{
    func setSubTextColor(pSubString : String, pColor : UIColor){    
        let attributedString: NSMutableAttributedString = self.attributedText != nil ? NSMutableAttributedString(attributedString: self.attributedText!) : NSMutableAttributedString(string: self.text!);

        let range = attributedString.mutableString.range(of: pSubString, options:NSString.CompareOptions.caseInsensitive)
        if range.location != NSNotFound {
            attributedString.addAttribute(NSForegroundColorAttributeName, value: pColor, range: range);
        }
        self.attributedText = attributedString
    }
}
2
Dipak Panchasara

Swift 4.2

extension UILabel {

    func boldSubstring(_ substr: String) {
        guard substr.isEmpty == false,
            let text = attributedText,
            let range = text.string.range(of: substr, options: .caseInsensitive) else {
                return
        }
        let attr = NSMutableAttributedString(attributedString: text)
        let start = text.string.distance(from: text.string.startIndex, to: range.lowerBound)
        let length = text.string.distance(from: range.lowerBound, to: range.upperBound)
        attr.addAttributes([NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: self.font.pointSize)],
                           range: NSMakeRange(start, length))
        attributedText = attr
    }
}
1
Debaprio B

Ce sera vraiment facile de résoudre votre problème avec la bibliothèque que j'ai créée. Cela s'appelle Atributika.

let calculatedCoffee: Int = 768
let g = Style("g").font(.boldSystemFont(ofSize: 12)).foregroundColor(.red)
let all = Style.font(.systemFont(ofSize: 12))

let str = "\(calculatedCoffee)<g>g</g>".style(tags: g)
    .styleAll(all)
    .attributedString

label.attributedText = str

 768g

Vous pouvez le trouver ici https://github.com/psharanda/Atributika

1
Pavel Sharanda

Swifter Swift a une façon très douce de le faire sans aucun travail vraiment. Indiquez simplement le modèle qui doit être mis en correspondance et les attributs à appliquer. Ils sont parfaits pour beaucoup de choses, consultez-les.

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

Si vous utilisez plusieurs endroits et que vous voulez que cela se produise uniquement dans des cas spécifiques, cette méthode ne fonctionnera pas.

Vous pouvez le faire en une étape, simplement plus facile à lire quand ils sont séparés.

0
Vrezh Gulyan

Swift 5 et plus

   let attributedString = NSAttributedString(string:"targetString",
                                   attributes:[NSAttributedString.Key.foregroundColor: UIColor.lightGray,
                                               NSAttributedString.Key.font: UIFont(name: "Arial", size: 18.0) as Any])
0
midhun p

Swift 4.x

let attr = [NSForegroundColorAttributeName:self.configuration.settingsColor, NSFontAttributeName: self.configuration.settingsFont]

let title = NSAttributedString(string: self.configuration.settingsTitle,
                               attributes: attr)
0
Das

Swift 3.0 // créer une chaîne attribuée

Définir des attributs comme

let attributes = [NSAttributedStringKey.font : UIFont.init(name: "Avenir-Medium", size: 13.0)]
0
Sidharth Khanna

Veuillez envisager d'utiliser Prestyler

import Prestyler
...
Prestyle.defineRule("$", UIColor.red)
label.attributedText = "\(calculatedCoffee) $g$".prestyled()
0
Kruiller