nsattributedstring core-text line-spacing

Texto central: la altura de la línea NSAttributedString se realiza correctamente?



core-text line-spacing (6)

Estoy completamente a oscuras con el espaciado de líneas de Core Text. Estoy usando NSAttributedString y especifico los siguientes atributos en él: - kCTFontAttributeName - kCTParagraphStyleAttributeName

A partir de esto, CTFrameSetter se crea y se dibuja en contexto.

En el atributo de estilo de párrafo me gustaría especificar la altura de las líneas.

Cuando uso kCTParagraphStyleSpecifierLineHeightMultiple, cada línea recibe un relleno en la parte superior del texto, en lugar de que el texto se muestre en la mitad de esta altura.

Cuando uso kCTParagraphStyleSpecifierLineSpacing, se agrega un relleno en la parte inferior del texto.

Por favor, ayúdeme a lograr una altura de línea específica con el texto (glifos) en el medio de esa altura, en lugar de que el texto se encuentre en la parte inferior o superior de la línea.

¿No es esto posible sin seguir el camino de la creación explícita de CTLine y así sucesivamente?


En Swift 3 :

let textFont = UIFont(name: "Helvetica Bold", size: 20)! let textColor = UIColor(white: 1, alpha: 1) // White let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.paragraphSpacing = 20 // Paragraph Spacing paragraphStyle.lineSpacing = 40 // Line Spacing let textFontAttributes = [ NSFontAttributeName: textFont, NSForegroundColorAttributeName: textColor, NSParagraphStyleAttributeName: paragraphStyle ] as [String : Any]


Esto funcionó para mí en Xcode 7.2. iOS 9.2.1. (Swift 2.1.):

dispatch_async(dispatch_get_main_queue()) { () -> Void in let paragraphStyleWithSpacing = NSMutableParagraphStyle() paragraphStyleWithSpacing.lineSpacing = 2.0 //CGFloat let textWithLineSpacing = NSAttributedString(string: str, attributes: [NSParagraphStyleAttributeName : paragraphStyleWithSpacing]) self.MY_TEXT_VIEW_NAME.attributedText = textWithLineSpacing }


Hay dos propiedades de NSParagraphStyle que modifican la altura entre las líneas de base de texto sucesivas en el mismo párrafo : lineSpacing y lineHeightMultiple . @Schoob tiene razón en que un lineHeightMultiple encima de 1.0 agrega espacio adicional sobre el texto, mientras que un lineSpacing encima de 0.0 agrega espacio por debajo del texto. Este diagrama muestra cómo se relacionan las distintas dimensiones.

Para lograr que el texto permanezca centrado, el objetivo es, por lo tanto, especificar uno en términos del otro, de tal manera que cualquier ''relleno'' que agreguemos por un atributo (arriba / abajo) se equilibre determinando el relleno del otro atributo (abajo / arriba) a juego. En otras palabras, cualquier espacio adicional agregado se distribuye de manera uniforme y al mismo tiempo se conserva el posicionamiento existente del texto.

Lo bueno es que de esta manera puede elegir qué atributo desea especificar y luego determinar el otro:

extension UIFont { func lineSpacingToMatch(lineHeightMultiple: CGFloat) -> CGFloat { return self.lineHeight * (lineHeightMultiple - 1) } func lineHeightMultipleToMatch(lineSpacing: CGFloat) -> CGFloat { return 1 + lineSpacing / self.lineHeight } }

Desde aquí, otras respuestas muestran cómo estos dos atributos se pueden establecer en una NSAttributedString , pero esto debería responder cómo los dos pueden relacionarse para "centrar" el texto.


Puede configurar / actualizar el espaciado de línea y la altura de línea de forma múltiple desde el guión gráfico, así como programáticamente.

Desde Interface Builder:

Programmáticamente:

SWIFT 4

extension UILabel { // Pass value for any one of both parameters and see result func setLineSpacing(lineSpacing: CGFloat = 0.0, lineHeightMultiple: CGFloat = 0.0) { guard let labelText = self.text else { return } let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineSpacing = lineSpacing paragraphStyle.lineHeightMultiple = lineHeightMultiple let attributedString:NSMutableAttributedString if let labelattributedText = self.attributedText { attributedString = NSMutableAttributedString(attributedString: labelattributedText) } else { attributedString = NSMutableAttributedString(string: labelText) } // Line spacing attribute // Swift 4.2++ attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, attributedString.length)) // Swift 4.1-- attributedString.addAttribute(NSAttributedStringKey.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, attributedString.length)) self.attributedText = attributedString } }

Ahora llame a la función de extensión

let label = UILabel() let stringValue = "How to/ncontrol/nthe/nline spacing/nin UILabel" // Pass value for any one argument - lineSpacing or lineHeightMultiple label.setLineSpacing(lineSpacing: 2.0) . // try values 1.0 to 5.0 // or try lineHeightMultiple //label.setLineSpacing(lineHeightMultiple = 2.0) // try values 0.5 to 2.0

O usando una instancia de etiqueta (solo copie y ejecute este código para ver el resultado)

let label = UILabel() let stringValue = "How to/ncontrol/nthe/nline spacing/nin UILabel" let attrString = NSMutableAttributedString(string: stringValue) var style = NSMutableParagraphStyle() style.lineSpacing = 24 // change line spacing between paragraph like 36 or 48 style.minimumLineHeight = 20 // change line spacing between each line like 30 or 40 // Swift 4.2++ // Line spacing attribute attrString.addAttribute(NSAttributedString.Key.paragraphStyle, value: style, range: NSRange(location: 0, length: stringValue.characters.count)) // Character spacing attribute attrString.addAttribute(NSAttributedString.Key.kern, value: 2, range: NSMakeRange(0, attrString.length)) // Swift 4.1-- // Line spacing attribute attrString.addAttribute(NSAttributedStringKey.paragraphStyle, value: style, range: NSRange(location: 0, length: stringValue.characters.count)) // Character spacing attribute attrString.addAttribute(NSAttributedStringKey.kern, value: 2, range: NSMakeRange(0, attrString.length)) label.attributedText = attrString

Swift 3

let label = UILabel() let stringValue = "How to/ncontrol/nthe/nline spacing/nin UILabel" let attrString = NSMutableAttributedString(string: stringValue) var style = NSMutableParagraphStyle() style.lineSpacing = 24 // change line spacing between paragraph like 36 or 48 style.minimumLineHeight = 20 // change line spacing between each line like 30 or 40 attrString.addAttribute(NSParagraphStyleAttributeName, value: style, range: NSRange(location: 0, length: stringValue.characters.count)) label.attributedText = attrString


Puedes usar esto si estás desarrollando para iOS> = 6.0

NSInteger strLength = [myString length]; NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init]; [style setLineSpacing:24]; [attString addAttribute:NSParagraphStyleAttributeName value:style range:NSMakeRange(0, strLength)];


Todavía no estoy 100% seguro de mis siguientes afirmaciones, pero parece tener sentido. Por favor corrígeme donde me equivoque.

La altura de la línea (líder) se refiere a la distancia entre las líneas de base de las líneas sucesivas de tipo. La línea base aquí se puede interpretar como la línea imaginaria sobre la que se asienta el texto.

El espaciamiento es el espacio entre líneas. El espacio aparece después de la línea de texto.

Terminé usando la siguiente solución a mi problema:

// NOT SURE WHAT THE THEORY BEHIND THIS FACTOR IS. WAS FOUND VIA TRIAL AND ERROR. CGFloat factor = 14.5/30.5; CGFloat floatValues[4]; floatValues[0] = self.lineHeight * factor/(factor + 1); floatValues[1] = self.lineHeight/(factor + 1); floatValues[2] = self.lineHeight;

Esta matriz se usa con el parámetro de estilo de párrafo para NSAttributedString:

CTParagraphStyleSetting paragraphStyle[3]; paragraphStyle[0].spec = kCTParagraphStyleSpecifierLineSpacing; paragraphStyle[0].valueSize = sizeof(CGFloat); paragraphStyle[0].value = &floatValues[0]; paragraphStyle[1].spec = kCTParagraphStyleSpecifierMinimumLineHeight; paragraphStyle[1].valueSize = sizeof(CGFloat); paragraphStyle[1].value = &floatValues[1]; paragraphStyle[2].spec = kCTParagraphStyleSpecifierMaximumLineHeight; paragraphStyle[2].valueSize = sizeof(CGFloat); paragraphStyle[2].value = &floatValues[2]; CTParagraphStyleRef style = CTParagraphStyleCreate((const CTParagraphStyleSetting*) &paragraphStyle, 3); [attributedString addAttribute:(NSString*)kCTParagraphStyleAttributeName value:(id)style range:NSMakeRange(0, [string length])]; CFRelease(style);

Espero que esto ayude a alguien. Actualizaré esta respuesta a medida que descubra información más relevante.