iOS 8: cambie el espaciado de caracteres en UILabel dentro de Interface Builder
swift interface-builder (11)
¿Hay alguna forma de cambiar el espaciado entre caracteres (pista) en el texto de UILabel usando Interface Builder? Si no, ¿hay alguna manera de hacerlo programáticamente en una UILabel existente que ya se haya creado con texto atribuido?
¡¡prueba esto!!
crear clases CustomLabel
@interface CustomLabel : UILabel
@property (assign, nonatomic) CGFloat myLineSpacing;
@end
@implementation CustomLabel
- (void)setMyLineSpacing:(CGFloat)myLineSpacing {
_myLineSpacing = myLineSpacing;
self.text = self.text;
}
- (void)setText:(NSString *)text {
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineSpacing = _myLineSpacing;
paragraphStyle.alignment = self.textAlignment;
NSDictionary *attributes = @{NSParagraphStyleAttributeName: paragraphStyle};
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text
attributes:attributes];
self.attributedText = attributedText;
}
y establecer el atributo de tiempo de ejecución
Tenga en cuenta que esto es en realidad el espaciado entre líneas (también llamado líder) . En los viejos tiempos (pre-digital) colocaba plomo (el metal) entre las líneas para aumentar el espacio entre líneas. Para espaciar entre letras , eso se denomina kerning . A continuación, le mostramos cómo hacer kerning https://.com/a/21141156/294884
Aquí hay una solución para Swift 4 que no anulará los atributos de texto existentes:
extension UILabel { /** Add kerning to a UILabel''s existing `attributedText` - note: If `UILabel.attributedText` has not been set, the `UILabel.text` value will be returned from `attributedText` by default - note: This method must be called each time `UILabel.text` or `UILabel.attributedText` has been set - parameter kernValue: The value of the kerning to add */ func addKern(_ kernValue: CGFloat) { guard let attributedText = attributedText, attributedText.string.count > 0, let fullRange = attributedText.string.range(of: attributedText.string) else { return } let updatedText = NSMutableAttributedString(attributedString: attributedText) updatedText.addAttributes([ .kern: kernValue ], range: NSRange(fullRange, in: attributedText.string)) self.attributedText = updatedText } }
Inspirada en la respuesta de Budidinho, esta es una solución más flexible para cuando desee cambiar el espacio entre etiquetas con diferentes espacios entre líneas. En lugar de ir dentro de la función y cambiar el valor, puede pasarlo como parámetro.
extension UILabel {
func addCharactersSpacing(_ value: CGFloat = 1.15) {
if let textString = text {
let attrs: [NSAttributedStringKey : Any] = [.kern: value]
attributedText = NSAttributedString(string: textString, attributes: attrs)
}
}
}
Para texto completamente estático, como el encabezado de una vista o especialmente la pantalla de inicio , puede insertar letras que ocupan una pequeña cantidad de ancho (por ejemplo, el carácter ''l'') con 0 opacity
. Alternativamente, establezca su color al mismo fondo.
Soy consciente del hecho de que esa no es la solución más bonita, pero es la única solución que funciona sin escribir ningún código y hace el trabajo, hasta que puedas hacerlo especificando los atributos en Xcode.
Editar / Idea adicional: para que el espaciado sea aún más variable, puede cambiar el tamaño de fuente de los caracteres de relleno en el medio. (Gracias a @mohamede1945 por esa idea)
Por qué todos ustedes están definiendo NSMUTABLEAttributedString. No tiene que establecer el rango explícitamente. Hace emojis se ve raro a veces. Esta es mi solución, probada en Swift 4 . 👍
extension UILabel {
func setTextSpacingBy(value: Double) {
if let textString = self.text {
let attributedString = NSMutableAttributedString(string: textString)
attributedString.addAttribute(NSKernAttributeName, value: value, range: NSRange(location: 0, length: attributedString.length - 1))
attributedText = attributedString
}
}
}
Prueba esto. Agregará el espaciado de caracteres que asigne, ya sea que configure texto simple o texto atribuido.
open class UHBCustomLabel : UILabel {
@IBInspectable open var characterSpacing:CGFloat = 1 {
didSet {
updateWithSpacing()
}
}
open override var text: String? {
set {
super.text = newValue
updateWithSpacing()
}
get {
return super.text
}
}
open override var attributedText: NSAttributedString? {
set {
super.attributedText = newValue
updateWithSpacing()
}
get {
return super.attributedText
}
}
func updateWithSpacing() {
let attributedString = self.attributedText == nil ? NSMutableAttributedString(string: self.text ?? "") : NSMutableAttributedString(attributedString: attributedText!)
attributedString.addAttribute(NSKernAttributeName, value: self.characterSpacing, range: NSRange(location: 0, length: attributedString.length))
super.attributedText = attributedString
}
}
Si intenta hacer esto para su pantalla de inicio, simplemente cree una imagen del texto en otra herramienta de software. No se puede localizar la pantalla de inicio de todos modos, por lo que se evitan los enfoques poco convencionales.
Swift 3.2 & Interface Builder
extension UILabel {
@IBInspectable
var letterSpace: CGFloat {
set {
let attributedString: NSMutableAttributedString!
if let currentAttrString = attributedText {
attributedString = NSMutableAttributedString(attributedString: currentAttrString)
}
else {
attributedString = NSMutableAttributedString(string: text ?? "")
text = nil
}
attributedString.addAttribute(NSKernAttributeName,
value: newValue,
range: NSRange(location: 0, length: attributedString.length))
attributedText = attributedString
}
get {
if let currentLetterSpace = attributedText?.attribute(NSKernAttributeName, at: 0, effectiveRange: .none) as? CGFloat {
return currentLetterSpace
}
else {
return 0
}
}
}
}
Terminó usando esto por ahora para obtener texto atribuido existente y modificarlo para agregar espacio entre caracteres:
let attributedString = discoveryTitle.attributedText as NSMutableAttributedString
attributedString.addAttribute(NSKernAttributeName, value: 1.0, range: NSMakeRange(0, attributedString.length))
discoveryTitle.attributedText = attributedString
Swift 3:
let attributedString = NSMutableAttributedString(string: discoveryTitle.text)
attributedString.addAttribute(NSKernAttributeName, value: CGFloat(1.0), range: NSRange(location: 0, length: attributedString.length))
discoveryTitle.attributedText = attributedString
Usar NSRange en lugar de NSMakeRange funciona en Swift 3.
Enfoque de programación. (Prueba esto, debería funcionar para ti)
Nota: Probé en Swift 4
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
// 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
Sé que no es una solución de Interface Builder, pero puedes crear una extensión UILabel
y luego agregar espacio a cualquier UILabel
que quieras:
extension UILabel {
func addCharacterSpacing(kernValue: Double = 1.15) {
if let labelText = text, labelText.count > 0 {
let attributedString = NSMutableAttributedString(string: labelText)
attributedString.addAttribute(NSAttributedStringKey.kern, value: kernValue, range: NSRange(location: 0, length: attributedString.length - 1))
attributedText = attributedString
}
}
}
Considere cambiar el kernValue
predeterminado de 1.15
a algo que funcione mejor con su diseño.
Al implementar, siempre agregue espaciado de caracteres después de establecer el valor del texto:
myLabel.text = "We used to be so close"
myLabel.addCharacterSpacing()
Si planea tener espaciado diferente en diferentes lugares de la aplicación, puede anular el valor predeterminado de kern:
myLabelWithSpecialNeeds.addCharacterSpacing(kernValue: 1.3)