Subrayar texto en UIlabel

¿Cómo puedo subrayar un texto que podría ser varias líneas de cadena? Encuentro que algunas personas sugieren UIWebView, pero obviamente es una clase demasiado pesada para el procesamiento de texto.

Mi idea era descubrir el punto inicial y la longitud de cada cuerda en cada línea. Y dibuja una línea debajo de ella en consecuencia.

Me encuentro con problemas para saber la longitud y el punto de inicio de la cuerda. ¿Puede alguien ayudarme con esto?

Intenté usar -[UILabel textRectForBounds:limitedToNumberOfLines:] , este debería ser el resumen del texto para el texto, ¿no? Entonces, ¿tengo que trabajar en la alineación? ¿Cómo puedo obtener el punto de inicio de cada línea cuando está justificado al centro y justificado a la derecha?

Soy nuevo aquí, así que gracias de antemano.

Puede subclasificar desde UILabel y anular el método drawRect:

 - (void)drawRect:(CGRect)rect { CGContextRef ctx = UIGraphicsGetCurrentContext(); CGContextSetRGBStrokeColor(ctx, 207.0f/255.0f, 91.0f/255.0f, 44.0f/255.0f, 1.0f); // RGBA CGContextSetLineWidth(ctx, 1.0f); CGContextMoveToPoint(ctx, 0, self.bounds.size.height - 1); CGContextAddLineToPoint(ctx, self.bounds.size.width, self.bounds.size.height - 1); CGContextStrokePath(ctx); [super drawRect:rect]; } 

UPD:
A partir de iOS 6, Apple agregó soporte NSAttributedString para UILabel, por lo que ahora es mucho más fácil y funciona para múltiples líneas:

 NSDictionary *underlineAttribute = @{NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle)}; myLabel.attributedText = [[NSAttributedString alloc] initWithString:@"Test string" attributes:underlineAttribute]; 

Si aún desea admitir iOS 4 e iOS 5, le recomendaría utilizar TTTAttributedLabel en lugar de subrayar la etiqueta manualmente. Sin embargo, si necesita subrayar UILabel de una sola línea y no desea utilizar componentes de terceros, el código anterior aún funcionaría.

Esto es lo que hice. Funciona como la mantequilla.

1) Agregue CoreText.framework a sus Frameworks.

2) importe en la clase donde necesita la etiqueta subrayada.

3) Escribe el siguiente código.

  NSMutableAttributedString *attString = [[NSMutableAttributedString alloc] initWithString:@"My Messages"]; [attString addAttribute:(NSString*)kCTUnderlineStyleAttributeName value:[NSNumber numberWithInt:kCTUnderlineStyleSingle] range:(NSRange){0,[attString length]}]; self.myMsgLBL.attributedText = attString; self.myMsgLBL.textColor = [UIColor whiteColor]; 

En Swift:

  let underlineAttriString = NSAttributedString(string:"attriString", attributes: [NSUnderlineStyleAttributeName: NSUnderlineStyle.StyleSingle.rawValue]) label.attributedText = underlineAttriString 

Use una cadena de atributo:

 NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] initWithString:@"Your String"] [attrString addAttribute:(NSString*)kCTUnderlineStyleAttributeName value:[NSNumber numberWithInt:kCTUnderlineStyleSingle] range:(NSRange){0,[attrString length]}]; 

Y a continuación, anule la etiqueta – (void) drawTextInRect: (CGRect) aRect y represente el texto en algo así como:

 CGContextRef ctx = UIGraphicsGetCurrentContext(); CGContextSaveGState(ctx); CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attrString); drawingRect = self.bounds; CGMutablePathRef path = CGPathCreateMutable(); CGPathAddRect(path, NULL, drawingRect); textFrame = CTFramesetterCreateFrame(framesetter,CFRangeMake(0,0), path, NULL); CGPathRelease(path); CFRelease(framesetter); CTFrameDraw(textFrame, ctx); CGContextRestoreGState(ctx); 

O mejor aún, en lugar de anular solo use la etiqueta OHAttributedLabel creada por Olivier Halligon

He combinado algunas de las respuestas proporcionadas para crear una subclase UILabel (al menos para mis necesidades) que sea compatible con:

  • texto multilínea con varios límites de etiqueta (el texto puede estar en el medio del marco de la etiqueta o en el tamaño preciso)
  • subrayar
  • tachar
  • línea de subrayado / tachado offset
  • alineación del texto
  • diferentes tamaños de fuente

https://github.com/GuntisTreulands/UnderLineLabel

Las personas que no desean subclasificar la vista (UILabel / UIButton) etc … ‘forgetButton’ también pueden reemplazarse por cualquier etiqueta.

 -(void) drawUnderlinedLabel { NSString *string = [forgetButton titleForState:UIControlStateNormal]; CGSize stringSize = [string sizeWithFont:forgetButton.titleLabel.font]; CGRect buttonFrame = forgetButton.frame; CGRect labelFrame = CGRectMake(buttonFrame.origin.x + buttonFrame.size.width - stringSize.width, buttonFrame.origin.y + stringSize.height + 1 , stringSize.width, 2); UILabel *lineLabel = [[UILabel alloc] initWithFrame:labelFrame]; lineLabel.backgroundColor = [UIColor blackColor]; //[forgetButton addSubview:lineLabel]; [self.view addSubview:lineLabel]; } 
 NSString *tem =self.detailCustomerCRMCaseLabel.text; if (tem != nil && ![tem isEqualToString:@""]) { NSMutableAttributedString *temString=[[NSMutableAttributedString alloc]initWithString:tem]; [temString addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInt:1] range:(NSRange){0,[temString length]}]; self.detailCustomerCRMCaseLabel.attributedText = temString; } 

Otra solución podría ser (desde iOS 7) dado un valor negativo a NSBaselineOffsetAttributeName , por ejemplo, su NSAttributedString podría ser:

 NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:@"my text goes here' attributes:@{NSFontAttributeName: [UIFont fontWithName:@"Helvetica-Regular" size:12], NSForegroundColorAttributeName: [UIColor blackColor], NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle), NSBaselineOffsetAttributeName: @(-3)}]; 

Espero que esto ayude 😉

 NSMutableAttributedString *text = [self.myUILabel.attributedText mutableCopy]; [text addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:NSMakeRange(0, text.length)]; self.myUILabel.attributedText = text; 

Puede crear una etiqueta personalizada con el nombre UnderlinedLabel y editar la función drawRect.

 #import "UnderlinedLabel.h" @implementation UnderlinedLabel - (void)drawRect:(CGRect)rect { NSString *normalTex = self.text; NSDictionary *underlineAttribute = @{NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle)}; self.attributedText = [[NSAttributedString alloc] initWithString:normalTex attributes:underlineAttribute]; [super drawRect:rect]; } 

Aquí está la solución más fácil que funciona para mí sin escribir códigos adicionales.

 // To underline text in UILable NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithString:@"Type your text here"]; [text addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:NSMakeRange(0, text.length)]; lblText.attributedText = text; 

Una versión mejorada del código de Kovpas (color y tamaño de línea)

 @implementation UILabelUnderlined - (void)drawRect:(CGRect)rect { CGContextRef ctx = UIGraphicsGetCurrentContext(); const CGFloat* colors = CGColorGetComponents(self.textColor.CGColor); CGContextSetRGBStrokeColor(ctx, colors[0], colors[1], colors[2], 1.0); // RGBA CGContextSetLineWidth(ctx, 1.0f); CGSize tmpSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(200, 9999)]; CGContextMoveToPoint(ctx, 0, self.bounds.size.height - 1); CGContextAddLineToPoint(ctx, tmpSize.width, self.bounds.size.height - 1); CGContextStrokePath(ctx); [super drawRect:rect]; } @end 

He creado para uilabel multilínea con subrayado:

Para Tamaño de fuente 8 a 13 configure int lineHeight = self.font.pointSize + 3;

Para tamaño de fuente 14 a 20, configure int lineHeight = self.font.pointSize + 4;

 - (void)drawRect:(CGRect)rect { CGContextRef ctx = UIGraphicsGetCurrentContext(); const CGFloat* colors = CGColorGetComponents(self.textColor.CGColor); CGContextSetRGBStrokeColor(ctx, colors[0], colors[1], colors[2], 1.0); // RGBA CGContextSetLineWidth(ctx, 1.0f); CGSize tmpSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(self.frame.size.width, 9999)]; int height = tmpSize.height; int lineHeight = self.font.pointSize+4; int maxCount = height/lineHeight; float totalWidth = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(1000, 9999)].width; for(int i=1;i<=maxCount;i++) { float width=0.0; if((i*self.frame.size.width-totalWidth)<=0) width = self.frame.size.width; else width = self.frame.size.width - (i* self.frame.size.width - totalWidth); CGContextMoveToPoint(ctx, 0, lineHeight*i-1); CGContextAddLineToPoint(ctx, width, lineHeight*i-1); } CGContextStrokePath(ctx); [super drawRect:rect]; } 

Como ha demostrado kovpas, puede usar el cuadro delimitador en la mayoría de los casos, aunque no siempre se garantiza que el cuadro delimitador se ajuste perfectamente al texto. Una caja con una altura de 50 y un tamaño de letra de 12 puede que no brinde los resultados que desea dependiendo de la configuración de UILabel.

Consulte el UIString dentro de UILabel para determinar sus métricas exactas y utilícelas para ubicar mejor su subrayado, independientemente del recuadro delimitador o marco que lo contenga, utilizando el código de dibujo ya proporcionado por kovpas.

También debe mirar la propiedad “líder” de UIFont que da la distancia entre las líneas de base en función de una fuente en particular. La línea de base es donde desearía que se dibujara su subrayado.

Busque las adiciones de UIKit a NSString:

 (CGSize)sizeWithFont:(UIFont *)font //Returns the size of the string if it were to be rendered with the specified font on a single line. (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size // Returns the size of the string if it were rendered and constrained to the specified size. (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode //Returns the size of the string if it were rendered with the specified constraints. 

Utilizo una vista de línea de código abierto y simplemente lo agregué a las subvistas de los botones:

  UILabel *label = termsButton.titleLabel; CGRect frame = label.frame; frame.origin.y += frame.size.height - 1; frame.size.height = 1; SSLineView *line = [[SSLineView alloc] initWithFrame:frame]; line.lineColor = [UIColor lightGrayColor]; [termsButton addSubview:line]; 

Esto fue inspirado por Karim arriba.

Según las Respuestas de Kovpas & Damien Praca, aquí hay una implementación de UILabelUnderligned que también es compatible con textAlignemnt .

 #import  @interface UILabelUnderlined : UILabel @end 

y la implementación:

 #import "UILabelUnderlined.h" @implementation DKUILabel - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code } return self; } - (void)drawRect:(CGRect)rect { CGContextRef ctx = UIGraphicsGetCurrentContext(); const CGFloat* colors = CGColorGetComponents(self.textColor.CGColor); CGContextSetRGBStrokeColor(ctx, colors[0], colors[1], colors[2], 1.0); // RGBA CGContextSetLineWidth(ctx, 1.0f); CGSize textSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(200, 9999)]; // handle textAlignement int alignementXOffset = 0; switch (self.textAlignment) { case UITextAlignmentLeft: break; case UITextAlignmentCenter: alignementXOffset = (self.frame.size.width - textSize.width)/2; break; case UITextAlignmentRight: alignementXOffset = self.frame.size.width - textSize.width; break; } CGContextMoveToPoint(ctx, alignementXOffset, self.bounds.size.height - 1); CGContextAddLineToPoint(ctx, alignementXOffset+textSize.width, self.bounds.size.height - 1); CGContextStrokePath(ctx); [super drawRect:rect]; } @end 

Aquí hay otra solución más simple (el ancho del subrayado no es el más preciso, pero fue lo suficientemente bueno para mí)

Tengo un UIView (_view_underline) que tiene fondo blanco, altura de 1 píxel y actualizo su ancho cada vez que actualizo el texto

 // It's a shame you have to do custom stuff to underline text - (void) underline { float width = [[_txt_title text] length] * 10.0f; CGRect prev_frame = [_view_underline frame]; prev_frame.size.width = width; [_view_underline setFrame:prev_frame]; } 

NSUnderlineStyleAttributeName que toma un NSNumber (donde 0 no es subrayado) se puede agregar a un diccionario de atributos. No sé si esto es más fácil. Pero, fue más fácil para mis propósitos.

  NSDictionary *attributes; attributes = @{NSFontAttributeName:font, NSParagraphStyleAttributeName: style, NSUnderlineStyleAttributeName:[NSNumber numberWithInteger:1]}; [text drawInRect:CGRectMake(self.contentRect.origin.x, currentY, maximumSize.width, textRect.size.height) withAttributes:attributes];