fonts - attributed - ¿Cómo hago una cadena atribuida usando Swift?
nsattributedstring swift 3 (20)
¡Creé una herramienta en línea que va a resolver su problema! Puede escribir su cadena y aplicar estilos gráficamente, y la herramienta le proporciona un código objetivo y rápido para generar esa cadena.
También es de código abierto, así que siéntase libre de extenderlo y enviar PR.
Estoy tratando de hacer una calculadora de café simple. Necesito mostrar la cantidad de café en gramos. El símbolo "g" para gramos se debe adjuntar a mi UILabel que estoy usando para mostrar la cantidad. Los números en la UILabel están cambiando dinámicamente con la entrada del usuario bien, pero debo agregar una "g" minúscula al final de la cadena que tiene el formato diferente de los números de actualización. La "g" se debe adjuntar a los números para que a medida que el tamaño y la posición del número cambien, la "g" se "mueva" con los números. Estoy seguro de que este problema se ha resuelto antes, por lo que un enlace en la dirección correcta sería útil ya que he buscado en Google mi pequeño corazón.
He buscado en la documentación una cadena atribuida e incluso he degradado un "Creador de cadenas atribuido" de la tienda de aplicaciones, pero el código resultante está en Objective-C y estoy usando Swift. Lo que sería asombroso, y probablemente útil para otros desarrolladores que aprenden este idioma, es un claro ejemplo de cómo crear una fuente personalizada con atributos personalizados utilizando una cadena atribuida en Swift. La documentación para esto es muy confusa ya que no hay un camino muy claro sobre cómo hacerlo. Mi plan es crear la cadena atribuida y agregarla al final de mi cadena coffeeAmount.
var coffeeAmount: String = calculatedCoffee + attributedText
Donde CalculateCoffee es un Int convertido a una cadena y "attribText" es la "g" minúscula con una fuente personalizada que estoy tratando de crear. Tal vez estoy haciendo esto por el camino equivocado. Cualquier ayuda es apreciada!
Funciona bien en beta 6
let attrString = NSAttributedString(
string: "title-title-title",
attributes: NSDictionary(
object: NSFont(name: "Arial", size: 12.0),
forKey: NSFontAttributeName))
La mejor manera de acercarse a Attributed Strings en iOS es utilizando el editor de texto atribuido incorporado en el generador de interfaces y evite las codificaciones NSAtrributedStringKeys en sus archivos de origen.
Más tarde, puede reemplazar dinámicamente placehoderls en tiempo de ejecución utilizando esta extensión:
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
}
}
Agregue una etiqueta de guión gráfico con texto atribuido que tenga este aspecto.
Luego simplemente actualiza el valor cada vez que lo necesites así:
label.attributedText = initalAttributedString.replacing(placeholder: "<price>", with: newValue)
Asegúrese de guardar en initalAttributedString el valor original.
Puede comprender mejor este enfoque leyendo este artículo: https://medium.com/mobile-appetite/text-attributes-on-ios-the-effortless-approach-ff086588173e
Los atributos se pueden configurar directamente en swift 3 ...
let attributes = NSAttributedString(string: "String", attributes: [NSFontAttributeName : UIFont(name: "AvenirNext-Medium", size: 30)!,
NSForegroundColorAttributeName : UIColor .white,
NSTextEffectAttributeName : NSTextEffectLetterpressStyle])
Luego usa la variable en cualquier clase con atributos
Para mí, las soluciones anteriores no funcionaron al configurar un color o una propiedad específica.
Esto funcionó:
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
}
Recomendaría encarecidamente utilizar una biblioteca para cadenas atribuidas. Lo hace mucho más fácil cuando quiere, por ejemplo, una cadena con cuatro colores diferentes y cuatro fuentes diferentes. Aquí está mi favorito. Se llama SwiftyAttributes
Si quisieras hacer una cadena con cuatro colores diferentes y diferentes fuentes usando los atributos de 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
se mostraría como
Será realmente fácil resolver su problema con la biblioteca que creé. Se llama 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
Lo puedes encontrar aquí https://github.com/psharanda/Atributika
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
Swift utiliza la misma NSMutableAttributedString
que hace Obj-C. Se crea una instancia al pasar el valor calculado como una cadena:
var attributedString = NSMutableAttributedString(string:"/(calculatedCoffee)")
Ahora crea la cadena g
atribuida (heh). Nota: UIFont.systemFontOfSize(_)
ahora es un inicializador personalizable, por lo que debe ser desenvuelto antes de poder usarlo:
var attrs = [NSFontAttributeName : UIFont.systemFontOfSize(19.0)!]
var gString = NSMutableAttributedString(string:"g", attributes:attrs)
Y luego añadirlo:
attributedString.appendAttributedString(gString)
Luego puede configurar la UILabel para que muestre la NSAttributedString de esta manera:
myLabel.attributedText = attributedString
Swift: xcode 6.1
let font:UIFont? = UIFont(name: "Arial", size: 12.0)
let attrString = NSAttributedString(
string: titleData,
attributes: NSDictionary(
object: font!,
forKey: NSFontAttributeName))
Esta respuesta ha sido actualizada para Swift 4.0.
Referencia rápida
La forma general para hacer y establecer una cadena atribuida es así. Puede encontrar otras opciones comunes a continuación.
// create attributed string
let myString = "Swift Attributed String"
let myAttribute = [ NSAttributedStringKey.foregroundColor: UIColor.blue ]
let myAttrString = NSAttributedString(string: myString, attributes: myAttribute)
// set attributed text on a UILabel
myLabel.attributedText = myAttrString
let myAttribute = [ NSAttributedStringKey.foregroundColor: UIColor.blue ]
let myAttribute = [ NSAttributedStringKey.backgroundColor: UIColor.yellow ]
let myAttribute = [ NSAttributedStringKey.font: UIFont(name: "Chalkduster", size: 18.0)! ]
let myAttribute = [ NSAttributedStringKey.underlineStyle: NSUnderlineStyle.styleSingle.rawValue ]
let myShadow = NSShadow()
myShadow.shadowBlurRadius = 3
myShadow.shadowOffset = CGSize(width: 3, height: 3)
myShadow.shadowColor = UIColor.gray
let myAttribute = [ NSAttributedStringKey.shadow: myShadow ]
El resto de este post da más detalles para aquellos que estén interesados.
Atributos
Los atributos de cadena son solo un diccionario en forma de [NSAttributedStringKey: Any]
, donde NSAttributedStringKey
es el nombre clave del atributo y Any
es el valor de algún tipo. El valor podría ser una fuente, un color, un número entero u otra cosa. Hay muchos atributos estándar en Swift que ya han sido predefinidos. Por ejemplo:
- nombre de clave:
NSAttributedStringKey.font
, valor: unUIFont
- nombre de clave:
NSAttributedStringKey.foregroundColor
, valor: aUIColor
- nombre de clave:
NSAttributedStringKey.link
, valor: unNSURL
o unaString
Hay muchos otros Vea este enlace para más. Incluso puedes hacer tus propios atributos personalizados como:
nombre de clave:
NSAttributedStringKey.myName
, valor: algún tipo.
Si haces una extension :extension NSAttributedStringKey { static let myName = NSAttributedStringKey(rawValue: "myCustomAttributeKey") }
Creando atributos en Swift
Puede declarar atributos como declarar cualquier otro diccionario.
// single attributes declared one at a time
let singleAttribute1 = [ NSAttributedStringKey.foregroundColor: UIColor.green ]
let singleAttribute2 = [ NSAttributedStringKey.backgroundColor: UIColor.yellow ]
let singleAttribute3 = [ NSAttributedStringKey.underlineStyle: NSUnderlineStyle.styleDouble.rawValue ]
// multiple attributes declared at once
let multipleAttributes: [NSAttributedStringKey : Any] = [
NSAttributedStringKey.foregroundColor: UIColor.green,
NSAttributedStringKey.backgroundColor: UIColor.yellow,
NSAttributedStringKey.underlineStyle: NSUnderlineStyle.styleDouble.rawValue ]
// custom attribute
let customAttribute = [ NSAttributedStringKey.myName: "Some value" ]
Anote el valor en rawValue
que fue necesario para el valor de estilo de subrayado.
Debido a que los atributos son solo diccionarios, también puede crearlos creando un diccionario vacío y luego agregándole pares clave-valor. Si el valor contendrá varios tipos, entonces tiene que usar Any
como tipo. Aquí está el ejemplo de atributos multipleAttributes
de arriba, recreado de esta manera:
var multipleAttributes = [NSAttributedStringKey : Any]()
multipleAttributes[NSAttributedStringKey.foregroundColor] = UIColor.green
multipleAttributes[NSAttributedStringKey.backgroundColor] = UIColor.yellow
multipleAttributes[NSAttributedStringKey.underlineStyle] = NSUnderlineStyle.styleDouble.rawValue
Cadenas Atribuidas
Ahora que entiendes los atributos, puedes hacer cadenas atribuidas.
Inicialización
Hay algunas formas de crear cadenas atribuidas. Si solo necesita una cadena de solo lectura, puede usar NSAttributedString
. Aquí hay algunas maneras de inicializarlo:
// Initialize with a string only
let attrString1 = NSAttributedString(string: "Hello.")
// Initialize with a string and inline attribute(s)
let attrString2 = NSAttributedString(string: "Hello.", attributes: [NSAttributedStringKey.myName: "A value"])
// Initialize with a string and separately declared attribute(s)
let myAttributes1 = [ NSAttributedStringKey.foregroundColor: UIColor.green ]
let attrString3 = NSAttributedString(string: "Hello.", attributes: myAttributes1)
Si necesita cambiar los atributos o el contenido de la cadena más adelante, debe usar NSMutableAttributedString
. Las declaraciones son muy similares:
// 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: [NSAttributedStringKey.myName: "A value"])
// Initialize with a string and separately declared attribute(s)
let myAttributes2 = [ NSAttributedStringKey.foregroundColor: UIColor.green ]
let mutableAttrString4 = NSMutableAttributedString(string: "Hello.", attributes: myAttributes2)
Cambiar una cadena de atributos
Como ejemplo, vamos a crear la cadena atribuida en la parte superior de esta publicación.
Primero cree un NSMutableAttributedString
con un nuevo atributo de fuente.
let myAttribute = [ NSAttributedStringKey.font: UIFont(name: "Chalkduster", size: 18.0)! ]
let myString = NSMutableAttributedString(string: "Swift", attributes: myAttribute )
Si está trabajando a lo largo, establezca la cadena atribuida a un UITextView
(o UILabel
) como este:
textView.attributedText = myString
Usted no usa textView.text
.
Aquí está el resultado:
Luego, agregue otra cadena atribuida que no tenga ningún conjunto de atributos. (Tenga en cuenta que, aunque solía declarar myString
arriba, todavía puedo modificarlo porque es un NSMutableAttributedString
. Esto me parece bastante inoportuno y no me sorprendería si esto cambia en el futuro. Déjeme un comentario cuando eso NSMutableAttributedString
. sucede.)
let attrString = NSAttributedString(string: " Attributed Strings")
myString.append(attrString)
A continuación, seleccionaremos la palabra "Cadenas", que comienza en el índice 17
y tiene una longitud de 7
. Tenga en cuenta que se trata de un NSRange
y no de Swift Range
. (Consulte esta respuesta para obtener más información sobre los rangos). El método addAttribute
nos permite colocar el nombre de la clave de atributo en el primer punto, el valor del atributo en el segundo punto y el rango en el tercer lugar.
var myRange = NSRange(location: 17, length: 7) // range starting at location 17 with a lenth of 7: "Strings"
myString.addAttribute(NSAttributedStringKey.foregroundColor, value: UIColor.red, range: myRange)
Por último, vamos a añadir un color de fondo. Para addAttributes
, addAttributes
método addAttributes
(tenga en cuenta los s
). Podría agregar varios atributos a la vez con este método, pero solo agregaré uno nuevamente.
myRange = NSRange(location: 3, length: 17)
let anotherAttribute = [ NSAttributedStringKey.backgroundColor: UIColor.yellow ]
myString.addAttributes(anotherAttribute, range: myRange)
Observe que los atributos se superponen en algunos lugares. Agregar un atributo no sobrescribe un atributo que ya está allí.
Relacionado
- Cómo cambiar el texto de un
NSMutableAttributedString
pero mantener los atributos
Otras lecturas
- Cómo recuperar los atributos de una ubicación de tap
- Guía de programación de cadenas atribuidas (muy informativa pero desafortunadamente solo en Objective-C)
Swift 2.0
Aquí hay una muestra:
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
O
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
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
}
}
Swift 4:
let attributes = [NSAttributedStringKey.font: UIFont(name: "HelveticaNeue-Bold", size: 17)!,
NSAttributedStringKey.foregroundColor: UIColor.white]
Swift 4
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)
Necesitas eliminar el valor bruto en swift 4
Versión de Xcode 6 :
let attriString = NSAttributedString(string:"attriString", attributes:
[NSForegroundColorAttributeName: UIColor.lightGrayColor(),
NSFontAttributeName: AttriFont])
Versión 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])
let attrString = NSAttributedString (
string: "title-title-title",
attributes: [NSAttributedStringKey.foregroundColor: UIColor.black])
cell.lblFrom.attributedText = decorateText(sub: sender!, des: " - /(convertDateFormatShort3(myDateString: datetime!))")
//Implementación
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)
extension String {
//MARK: Getting customized string
struct StringAttribute {
var fontName = "HelveticaNeue-Bold"
var fontSize: CGFloat?
var initialIndexOftheText = 0
var lastIndexOftheText: Int?
var textColor: UIColor = .black
var backGroundColor: UIColor = .clear
var underLineStyle: NSUnderlineStyle = .styleNone
var textShadow: TextShadow = TextShadow()
var fontOfText: UIFont {
if let font = UIFont(name: fontName, size: fontSize!) {
return font
} else {
return UIFont(name: "HelveticaNeue-Bold", size: fontSize!)!
}
}
struct TextShadow {
var shadowBlurRadius = 0
var shadowOffsetSize = CGSize(width: 0, height: 0)
var shadowColor: UIColor = .clear
}
}
func getFontifiedText(partOfTheStringNeedToConvert partTexts: [StringAttribute]) -> NSAttributedString {
let fontChangedtext = NSMutableAttributedString(string: self, attributes: [NSFontAttributeName: UIFont(name: "HelveticaNeue-Bold", size: (partTexts.first?.fontSize)!)!])
for eachPartText in partTexts {
let lastIndex = eachPartText.lastIndexOftheText ?? self.count
let attrs = [NSFontAttributeName : eachPartText.fontOfText, NSForegroundColorAttributeName: eachPartText.textColor, NSBackgroundColorAttributeName: eachPartText.backGroundColor, NSUnderlineStyleAttributeName: eachPartText.underLineStyle, NSShadowAttributeName: eachPartText.textShadow ] as [String : Any]
let range = NSRange(location: eachPartText.initialIndexOftheText, length: lastIndex - eachPartText.initialIndexOftheText)
fontChangedtext.addAttributes(attrs, range: range)
}
return fontChangedtext
}
}
// Utilízalo como abajo
let someAttributedText = "Some Text".getFontifiedText(partOfTheStringNeedToConvert: <#T##[String.StringAttribute]#>)
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
}
}