Cambiar el color de un texto específico usando NSMutableAttributedString en Swift


100

El problema que tengo es que quiero poder cambiar el color de texto de cierto texto en un TextView. Estoy usando una cadena concatenada y solo quiero las cadenas que agrego al texto de TextView. Parece que lo que quiero usar es NSMutableAttributedString, pero no encuentro ningún recurso sobre cómo usar esto en Swift. Lo que tengo hasta ahora es algo como esto:

let string = "A \(stringOne) with \(stringTwo)"
var attributedString = NSMutableAttributedString(string: string)
textView.attributedText = attributedString

Desde aquí, sé que necesito encontrar el rango de palabras que deben cambiar su color de texto y luego agregarlas a la cadena atribuida. Lo que necesito saber es cómo encontrar las cadenas correctas del atributoString y luego cambiar su color de texto.

Como tengo una calificación demasiado baja, no puedo responder mi propia pregunta, pero aquí está la respuesta que encontré

Encontré mi propia respuesta traduciendo de la traducción de un código de

Cambiar atributos de subcadenas en una NSAttributedString

Aquí está el ejemplo de implementación en Swift:

let string = "A \(stringOne) and \(stringTwo)"
var attributedString = NSMutableAttributedString(string:string)

let stringOneRegex = NSRegularExpression(pattern: nameString, options: nil, error: nil)
let stringOneMatches = stringOneRegex.matchesInString(longString, options: nil, range: NSMakeRange(0, attributedString.length))
for stringOneMatch in stringOneMatches {
    let wordRange = stringOneMatch.rangeAtIndex(0)
    attributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.nameColor(), range: wordRange)
}

textView.attributedText = attributedString

Como quiero cambiar el color de texto de varias cadenas, crearé una función auxiliar para manejar esto, pero esto funciona para cambiar el color de texto.


¿Sabes cómo hacerlo en Objective-C? ¿Ha intentado reescribir ese mismo código en Swift?
Aaron Brager

Aquí hay una muy buena respuesta: stackoverflow.com/a/37992022/426571
el_quick

Respuestas:


110

Veo que ha respondido la pregunta de alguna manera, pero para proporcionar una forma un poco más concisa sin usar expresiones regulares para responder a la pregunta del título:

Para cambiar el color de una longitud de texto, debe conocer el índice de inicio y finalización de los caracteres que se van a colorear en la cadena, por ejemplo

var main_string = "Hello World"
var string_to_color = "World"

var range = (main_string as NSString).rangeOfString(string_to_color)

Luego, convierte a una cadena atribuida y usa 'agregar atributo' con NSForegroundColorAttributeName:

var attributedString = NSMutableAttributedString(string:main_string)
attributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor() , range: range)

Puede encontrar una lista de otros atributos estándar que puede establecer en la documentación de Apple


20
NSColor es solo para OSX - use UIColor para IOS
Steve O'Connor

1
¿Qué sucede si tengo var main_string = "Hola mundo Hola mundo Hola mundo" y necesito aplicar color en "Mundo" en toda la cadena?
msmq

main_string, string_to_colory rangenunca fueron mutados. ¿Considera cambiarlos a letconstante?
Cesare

Buena solucion. Me has salvado el día.
Sagar Chauhan

106

SWIFT 5

let main_string = "Hello World"
let string_to_color = "World"

let range = (main_string as NSString).range(of: string_to_color)

let attribute = NSMutableAttributedString.init(string: main_string)
attribute.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.red , range: range)


txtfield1 = UITextField.init(frame:CGRect(x:10 , y:20 ,width:100 , height:100))
txtfield1.attributedText = attribute

SWIFT 4.2

 let txtfield1 :UITextField!

    let main_string = "Hello World"
    let string_to_color = "World"

    let range = (main_string as NSString).range(of: string_to_color)

    let attribute = NSMutableAttributedString.init(string: main_string)
    attribute.addAttribute(NSAttributedStringKey.foregroundColor, value: UIColor.red , range: range)


    txtfield1 = UITextField.init(frame:CGRect(x:10 , y:20 ,width:100 , height:100))
    txtfield1.attributedText = attribute

¿Qué pasa si la cadena es grande y tiene muchas palabras duplicadas (similares)? ¿Funciona el rango (de: ...)?
Hatim

44

Actualización Swift 2.1:

 let text = "We tried to make this app as most intuitive as possible for you. If you have any questions don't hesitate to ask us. For a detailed manual just click here."
 let linkTextWithColor = "click here"

 let range = (text as NSString).rangeOfString(linkTextWithColor)

 let attributedString = NSMutableAttributedString(string:text)
 attributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor() , range: range)

 self.helpText.attributedText = attributedString

self.helpTextes una UILabelsalida.


1
Oh Chris, eres mi héroe. Estoy buscando este bloque de código exactamente durante mucho tiempo.
Pan Mluvčí

@chris. Quiero cambiar la cadena nsmutableattributed en la vista de texto, ¿es eso posible?
Uma Madhavi

funciona para una sola palabra. pero en mi cadena hay varias palabras, es un cambio de color, pero luego escribo después de esa palabra de color rojo que el color de la palabra también es rojo. Entonces, ¿puede dar alguna solución si la tiene?
Dhaval Solanki

¡Gracias por tu ayuda!
ssowri1

18

Swift 4.2 y Swift 5 colorean partes de la cuerda.

Una forma muy fácil de usar NSMutableAttributedString mientras se extiende String. Esto también se puede utilizar para colorear más de una palabra en toda la cadena.

Agregue un nuevo archivo para extensiones, Archivo -> Nuevo -> Archivo Swift con nombre por ej. "NSAttributedString + TextColouring" y agregue el código

import UIKit

extension String {
    func attributedStringWithColor(_ strings: [String], color: UIColor, characterSpacing: UInt? = nil) -> NSAttributedString {
        let attributedString = NSMutableAttributedString(string: self)
        for string in strings {
            let range = (self as NSString).range(of: string)
            attributedString.addAttribute(NSAttributedString.Key.foregroundColor, value: color, range: range)
        }

        guard let characterSpacing = characterSpacing else {return attributedString}

        attributedString.addAttribute(NSAttributedString.Key.kern, value: characterSpacing, range: NSRange(location: 0, length: attributedString.length))

        return attributedString
    }
}

Ahora puede usar globalmente en cualquier controlador de vista que desee:

let attributedWithTextColor: NSAttributedString = "Doc, welcome back :)".attributedStringWithColor(["Doc", "back"], color: UIColor.black)

myLabel.attributedText = attributedWithTextColor

Ejemplo de uso de coloración de texto con swift 4


11

La respuesta ya se dio en publicaciones anteriores, pero tengo una forma diferente de hacer esto

Rápido 3x:

var myMutableString = NSMutableAttributedString()

myMutableString = NSMutableAttributedString(string: "Your full label textString")

myMutableString.setAttributes([NSFontAttributeName : UIFont(name: "HelveticaNeue-Light", size: CGFloat(17.0))!
        , NSForegroundColorAttributeName : UIColor(red: 232 / 255.0, green: 117 / 255.0, blue: 40 / 255.0, alpha: 1.0)], range: NSRange(location:12,length:8)) // What ever range you want to give

yourLabel.attributedText = myMutableString

¡Espero que esto ayude a alguien!


@UmaMadhavi ¿Cuál es exactamente su requisito?
Anurag Sharma

Quiero cambiar el tamaño y el color de la fuente en la vista de texto. Lo estoy obteniendo en nsmutableattributedstring.
Uma Madhavi

@UmaMadhavi mira este link1 y link2 . ¡Puede ser útil!
Anurag Sharma

Se bloquea si la fuente no está disponible.
SafeFastExpressive

10

La respuesta de Chris fue de gran ayuda para mí, así que usé su enfoque y lo convertí en una función que puedo reutilizar. Esto me permite asignar un color a una subcadena mientras le doy al resto de la cadena otro color.

static func createAttributedString(fullString: String, fullStringColor: UIColor, subString: String, subStringColor: UIColor) -> NSMutableAttributedString
{
    let range = (fullString as NSString).rangeOfString(subString)
    let attributedString = NSMutableAttributedString(string:fullString)
    attributedString.addAttribute(NSForegroundColorAttributeName, value: fullStringColor, range: NSRange(location: 0, length: fullString.characters.count))
    attributedString.addAttribute(NSForegroundColorAttributeName, value: subStringColor, range: range)
    return attributedString
}

6

Swift 4.1

NSAttributedStringKey.foregroundColor

por ejemplo, si desea cambiar la fuente en NavBar:

self.navigationController?.navigationBar.titleTextAttributes = [ NSAttributedStringKey.font: UIFont.systemFont(ofSize: 22), NSAttributedStringKey.foregroundColor: UIColor.white]

6

Puedes usar esta extensión, la pruebo

rápido 4.2

import Foundation
import UIKit

extension NSMutableAttributedString {

    convenience init (fullString: String, fullStringColor: UIColor, subString: String, subStringColor: UIColor) {
           let rangeOfSubString = (fullString as NSString).range(of: subString)
           let rangeOfFullString = NSRange(location: 0, length: fullString.count)//fullString.range(of: fullString)
           let attributedString = NSMutableAttributedString(string:fullString)
           attributedString.addAttribute(NSAttributedStringKey.foregroundColor, value: fullStringColor, range: rangeOfFullString)
           attributedString.addAttribute(NSAttributedStringKey.foregroundColor, value: subStringColor, range: rangeOfSubString)

           self.init(attributedString: attributedString)
   }

}

4

Swift 2.2

var myMutableString = NSMutableAttributedString()

myMutableString = NSMutableAttributedString(string: "1234567890", attributes: [NSFontAttributeName:UIFont(name: kDefaultFontName, size: 14.0)!])

myMutableString.addAttribute(NSForegroundColorAttributeName, value: UIColor(red: 0.0/255.0, green: 125.0/255.0, blue: 179.0/255.0, alpha: 1.0), range: NSRange(location:0,length:5))

self.lblPhone.attributedText = myMutableString

Recibo un error cuando hago esto. Creo que quieres esto sin .CGColor.
Bjorn Roche

@SarabjitSingh. ¿Cómo es posible esto para textview?
Uma Madhavi

@UmaMadhavi ... Solo necesita agregar self.textView.attributedText = myMutableString ..... Funcionará ...
Sarabjit Singh

4

La forma más fácil de hacer etiquetas con diferentes estilos como el color, la fuente, etc. es usar la propiedad "Atributos" en el Inspector de atributos. Simplemente elija parte del texto y cámbielo como desee

ingrese la descripción de la imagen aquí


1
Suponiendo que no estás cambiando las cadenas programáticamente
Alejandro Cumpa

4

Basado en las respuestas antes de crear una extensión de cadena

extension String {

func highlightWordsIn(highlightedWords: String, attributes: [[NSAttributedStringKey: Any]]) -> NSMutableAttributedString {
     let range = (self as NSString).range(of: highlightedWords)
     let result = NSMutableAttributedString(string: self)

     for attribute in attributes {
         result.addAttributes(attribute, range: range)
     }

     return result
    }
}

Puede pasar los atributos del texto al método

Llamar así

  let attributes = [[NSAttributedStringKey.foregroundColor:UIColor.red], [NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: 17)]]
  myLabel.attributedText = "This is a text".highlightWordsIn(highlightedWords: "is a text", attributes: attributes)

4

Swift 4.1

He cambiado de esto en Swift 3

let str = "Welcome "
let welcomeAttribute = [ NSForegroundColorAttributeName: UIColor.blue()]
let welcomeAttrString = NSMutableAttributedString(string: str, attributes: welcomeAttribute)

Y esto en Swift 4.0

let str = "Welcome "
let welcomeAttribute = [ NSAttributedStringKey.foregroundColor: UIColor.blue()]
let welcomeAttrString = NSMutableAttributedString(string: str, attributes: welcomeAttribute)

a Swift 4.1

let str = "Welcome "
let welcomeAttribute = [ NSAttributedStringKey(rawValue: NSForegroundColorAttributeName): UIColor.blue()]
let welcomeAttrString = NSMutableAttributedString(string: str, attributes: welcomeAttribute)

Funciona bien


¿Esto está cambiando toda la cadena? Este es el más legible para mí, pero ¿hay alguna manera de cambiar solo palabras específicas dentro de la cadena como pidió el OP?
Moondra

3

rápido 4.2

    let textString = "Hello world"
    let range = (textString as NSString).range(of: "world")
    let attributedString = NSMutableAttributedString(string: textString)

    attributedString.addAttribute(NSAttributedStringKey.foregroundColor, value: UIColor.red, range: range)
    self.textUIlable.attributedText = attributedString

2

Para todos los que buscan " Aplicar un color específico a varias palabras en el texto ", podemos hacerlo usando NSRegularExpression

 func highlight(matchingText: String, in text: String) {
    let attributedString  = NSMutableAttributedString(string: text)
    if let regularExpression = try? NSRegularExpression(pattern: "\(matchingText)", options: .caseInsensitive) {
        let matchedResults = regularExpression.matches(in: text, options: [], range: NSRange(location: 0, length: attributedString.length))
        for matched in matchedResults {
             attributedString.addAttributes([NSAttributedStringKey.backgroundColor : UIColor.yellow], range: matched.range)

        }
        yourLabel.attributedText = attributedString
    }
}

Enlace de referencia: https://gist.github.com/aquajach/4d9398b95a748fd37e88


¿Es posible usar su código en la aplicación MacOS Cocoa? Intenté usarlo en mi proyecto de cocoa, pero no hay .attributedText en cocoa NSTextView.
CaOs433

2

Esto podría funcionar para ti

let main_string = " User not found,Want to review ? Click here"
    let string_to_color = "Click here"

    let range = (main_string as NSString).range(of: string_to_color)

    let attribute = NSMutableAttributedString.init(string: main_string)
    attribute.addAttribute(NSAttributedStringKey.foregroundColor, value: UIColor.blue , range: range)

    lblClickHere.attributedText = attribute

1
Si bien este fragmento de código puede ser la solución, incluir una explicación realmente ayuda a mejorar la calidad de su publicación. Recuerde que está respondiendo a la pregunta para los lectores en el futuro, y es posible que esas personas no conozcan los motivos de su sugerencia de código.
HMD

2

Con esta sencilla función puedes asignar el texto y resaltar la palabra elegida.

También puede cambiar UITextView a UILabel , etc.

func highlightBoldWordAtLabel(textViewTotransform: UITextView, completeText: String, wordToBold: String){
    textViewToTransform.text = completeText
    let range = (completeText as NSString).range(of: wordToBold)
    let attribute = NSMutableAttributedString.init(string: completeText)

    attribute.addAttribute(NSAttributedString.Key.font, value: UIFont.boldSystemFont(ofSize: 16), range: range)
    attribute.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.black , range: range)
    textViewToTransform.attributedText = attribute
}

1

Para cambiar el color de la fuente, primero seleccione atribuido en lugar de simple como en la imagen de abajo

Luego, debe seleccionar el texto en el campo atribuido y luego seleccionar el botón de color en el lado derecho de las alineaciones. Esto cambiará el color.


1

Puede utilizar este método. Implementé este método en mi clase de utilidad común para acceder globalmente.

func attributedString(with highlightString: String, normalString: String, highlightColor: UIColor) -> NSMutableAttributedString {
    let attributes = [NSAttributedString.Key.foregroundColor: highlightColor]
    let attributedString = NSMutableAttributedString(string: highlightString, attributes: attributes)
    attributedString.append(NSAttributedString(string: normalString))
    return attributedString
}

0

Si está utilizando Swift 3x y UITextView, tal vez NSForegroundColorAttributeName no funcione (no me funcionó sin importar el enfoque que intenté).

Entonces, después de investigar un poco, encontré una solución.

//Get the textView somehow
let textView = UITextView()
//Set the attributed string with links to it
textView.attributedString = attributedString
//Set the tint color. It will apply to the link only
textView.tintColor = UIColor.red

0

Manera súper fácil de hacer esto.

let text = "This is a colorful attributed string"
let attributedText = 
NSMutableAttributedString.getAttributedString(fromString: text)
attributedText.apply(color: .red, subString: "This")
//Apply yellow color on range
attributedText.apply(color: .yellow, onRange: NSMakeRange(5, 4))

Para obtener más detalles, haga clic aquí: https://github.com/iOSTechHub/AttributedString


0

Necesita cambiar los parámetros de la vista de texto, no los parámetros de la cadena atribuida

textView.linkTextAttributes = [
        NSAttributedString.Key.foregroundColor: UIColor.red,
        NSAttributedString.Key.underlineColor: UIColor.red,
        NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue
    ]

0

Por favor, consulte Cocoapod Prestyler :

Prestyler.defineRule("$", UIColor.orange)
label.attributedText = "This $text$ is orange".prestyled()

0
extension String{
// to make text field mandatory * looks
mutating func markAsMandatoryField()-> NSAttributedString{

    let main_string = self
    let string_to_color = "*"
    let range = (main_string as NSString).range(of: string_to_color)
    print("The rang = \(range)")
    let attribute = NSMutableAttributedString.init(string: main_string)
    attribute.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.rgbColor(red: 255.0, green: 0.0, blue: 23.0) , range: range)
     return attribute
}

}

use EmailLbl.attributedText = EmailLbl.text! .markAsMandatoryField ()


0

Puedes usar como extensión simple

extension String{

func attributedString(subStr: String) -> NSMutableAttributedString{
    let range = (self as NSString).range(of: subStr)
    let attributedString = NSMutableAttributedString(string:self)
    attributedString.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.red , range: range)
    
    return attributedString
  }
}

myLable.attributedText = fullStr.attributedString(subStr: strToChange)

  
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.