ios ios6 uilabel nsattributedstring

ios - Texto de alineación superior de diferentes tamaños dentro de una UILabel



ios6 nsattributedstring (4)

¿Cómo alinear al máximo el texto de diferentes tamaños dentro de una UILabel? Un ejemplo es la alineación superior de una cantidad de centavos más pequeña con una cantidad de dólares de mayor tamaño en las pancartas de precios.

UILabel en iOS6 es compatible con NSAttributedString que me permite tener texto de diferentes tamaños en el mismo UILabel. Sin embargo, no parece tener un atributo para el texto de alineación superior. ¿Cuáles son las opciones para implementar esto? Me parece que lo mejor es proporcionar una lógica de dibujo personalizada para hacer una alineación superior basada en una clave de cadena atribuida personalizada, pero no tengo idea de cómo hacerlo.


El problema al tratar de hacer esto simplemente alineando los orígenes de los marcos es que los caracteres "normales" generalmente terminan con un relleno adicional alrededor de ellos porque la etiqueta debe acomodar a todos los caracteres de la fuente, incluidos los ascendentes altos y los descendientes largos. Notará en la imagen que publicó que si el "99" más pequeño fuera una etiqueta separada que tenía el mismo origen que el texto más grande, sería demasiado alto debido al punto más alto del signo del dólar.

Afortunadamente, UIFont nos brinda toda la información que necesitamos para hacer esto correctamente. Necesitamos medir el espacio ascendente vacío que usan las etiquetas y ajustar el posicionamiento relativo para tenerlo en cuenta, de este modo:

//Make sure the labels hug their contents [self.bigTextLabel sizeToFit]; [self.smallTextLabel sizeToFit]; //Figure out the "blank" space above normal character height for the big text UIFont *bigFont = self.bigTextLabel.font; CGFloat bigAscenderSpace = (bigFont.ascender - bigFont.capHeight); //Move the small text down by that ammount CGFloat smallTextOrigin = CGRectGetMinY(self.bigTextLabel.frame) + bigAscenderSpace; //Figure out the "blank" space above normal character height for the little text UIFont *smallFont = self.smallTextLabel.font; CGFloat smallAscenderSpace = smallFont.ascender - smallFont.capHeight; //Move the small text back up by that ammount smallTextOrigin -= smallAscenderSpace; //Actually assign the frames CGRect smallTextFrame = self.smallTextLabel.frame; smallTextFrame.origin.y = smallTextOrigin; self.smallTextLabel.frame = smallTextFrame;

(Este código asume que tiene dos propiedades de etiqueta llamadas bigTextLabel y smallTextLabel , respectivamente)

Editar:

Hacer esto sin dos etiquetas es bastante similar. Puede crear una subclase UIView personalizada y dibujar NSAttributedStrings en ella con el -drawInRect:options:context: (asegúrese de usar NSStringDrawingUsesLineFragmentOrigin en sus opciones). La matemática para calcular la alineación superior debe ser la misma, la única diferencia es que obtiene la fuente de la cadena atribuida mediante el atributo NSFontAttributeName , no la etiqueta. El video de la WWDC de 2012 sobre el dibujo de cadena atribuido es una buena referencia para esto.


Eso es muy malo. No tengo suficiente reputación para comentar la respuesta que usé bien después de una pequeña modificación. Solo quiero señalar que use smallfont para los centavos en lugar de la font , lo que podría ser un error tipográfico.

A continuación se muestra el código modificado

- (NSMutableAttributedString *)styleSalePriceLabel:(NSString *)salePrice withFont:(UIFont *)font { if ([salePrice rangeOfString:@"."].location == NSNotFound) { return [[NSMutableAttributedString alloc] initWithString:salePrice]; } else { NSRange range = [salePrice rangeOfString:@"."]; range.length = (salePrice.length - range.location); NSMutableAttributedString *stylizedPriceLabel = [[NSMutableAttributedString alloc] initWithString:salePrice]; UIFont *smallfont = [UIFont fontWithName:font.fontName size:(font.pointSize / 2)]; NSNumber *offsetAmount = @(font.capHeight - smallfont.capHeight); [stylizedPriceLabel addAttribute:NSFontAttributeName value:smallfont range:range]; [stylizedPriceLabel addAttribute:NSBaselineOffsetAttributeName value:offsetAmount range:range]; return stylizedPriceLabel; } }


Pude lograr el resultado deseado con una sola etiqueta.

Usando un poco de matemáticas, puede desplazar la línea de base del texto más pequeño para lograr el resultado deseado.

C objetivo

- (NSMutableAttributedString *)styleSalePriceLabel:(NSString *)salePrice withFont:(UIFont *)font { if ([salePrice rangeOfString:@"."].location == NSNotFound) { return [[NSMutableAttributedString alloc] initWithString:salePrice]; } else { NSRange range = [salePrice rangeOfString:@"."]; range.length = (salePrice.length - range.location); NSMutableAttributedString *stylizedPriceLabel = [[NSMutableAttributedString alloc] initWithString:salePrice]; UIFont *smallFont = [UIFont fontWithName:font.fontName size:(font.pointSize / 2)]; NSNumber *offsetAmount = @(font.capHeight - smallFont.capHeight); [stylizedPriceLabel addAttribute:NSFontAttributeName value:smallFont range:range]; [stylizedPriceLabel addAttribute:NSBaselineOffsetAttributeName value:offsetAmount range:range]; return stylizedPriceLabel; } }

Rápido

extension Range where Bound == String.Index { func asNSRange() -> NSRange { let location = self.lowerBound.encodedOffset let length = self.lowerBound.encodedOffset - self.upperBound.encodedOffset return NSRange(location: location, length: length) } } extension String { func asStylizedPrice(using font: UIFont) -> NSMutableAttributedString { let stylizedPrice = NSMutableAttributedString(string: self, attributes: [.font: font]) guard var changeRange = self.range(of: ".")?.asNSRange() else { return stylizedPrice } changeRange.length = self.count - changeRange.location // forgive the force unwrapping let changeFont = UIFont(name: font.fontName, size: (font.pointSize / 2))! let offset = font.capHeight - changeFont.capHeight stylizedPrice.addAttribute(.font, value: changeFont, range: changeRange) stylizedPrice.addAttribute(.baselineOffset, value: offset, range: changeRange) return stylizedPrice } }

Esto produce lo siguiente:


Un posible enfoque sería hacer que la etiqueta tenga el tamaño exacto del texto que está ingresando.

CGRect labelFrame; //Set the origin of the label to whatever you want labelFrame.size = [label.text sizeWithFont:label.font]; //If using NSString labelFrame.size = [label.text size]; //If using NSAttributedString label.frame = labelFrame;

Ver esta publicación SO similar para más detalles .