¿Cómo puedo subrayar un texto que podría tener varias líneas de cadena? Encuentro que algunas personas sugieren UIWebView, pero obviamente es una clase demasiado pesada para solo representar texto.
Mi pensamiento era averiguar el punto de inicio y la longitud de cada cuerda en cada línea. Y dibuja una línea debajo de ella en consecuencia.
Encuentro problemas sobre cómo calcular la longitud y el punto de inicio de la cuerda.
Intenté usar -[UILabel textRectForBounds:limitedToNumberOfLines:]
, este debería ser el rectángulo delimitador del dibujo para el texto, ¿verdad? ¿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 a la derecha?
Respuestas:
Puede crear una subclase de 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 y iOS 5, le recomiendo usar TTTAttributedLabel en lugar de subrayar la etiqueta manualmente. Sin embargo, si necesita subrayar UILabel de una línea y no desea utilizar componentes de terceros, el código anterior aún funcionaría.
fuente
En Swift:
let underlineAttriString = NSAttributedString(string: "attriString", attributes: [NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue]) label.attributedText = underlineAttriString
fuente
Esto es lo que hice. Funciona como mantequilla.
1) Agregue CoreText.framework a sus Frameworks.
2) importe <CoreText / CoreText.h> 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];
fuente
Utilice una cadena de atributos:
NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] initWithString:@"Your String"] [attrString addAttribute:(NSString*)kCTUnderlineStyleAttributeName value:[NSNumber numberWithInt:kCTUnderlineStyleSingle] range:(NSRange){0,[attrString length]}];
Y luego anule la etiqueta - (void) drawTextInRect: (CGRect) aRect y renderice el texto en algo 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, simplemente use OHAttributedLabel creado por Olivier Halligon
fuente
NSMutableAttributedString
He combinado algunas de las respuestas proporcionadas para crear una mejor subclase de UILabel (al menos para mis requisitos), que admite:
https://github.com/GuntisTreulands/UnderLineLabel
fuente
Las personas que no quieran subclasificar la vista (UILabel / UIButton), etc ... 'ForgetButton' también puede ser reemplazado 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]; }
fuente
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; }
fuente
Otra solución podría ser (desde iOS 7) dar un valor negativo a
NSBaselineOffsetAttributeName
, por ejemplo,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 ;-)
fuente
NSMutableAttributedString *text = [self.myUILabel.attributedText mutableCopy]; [text addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:NSMakeRange(0, text.length)]; self.myUILabel.attributedText = text;
fuente
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]; }
fuente
Esta es la solución más sencilla que me funciona 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;
fuente
A veces, el desarrollador se atasca en una pequeña parte de diseño de cualquier pantalla de interfaz de usuario. Uno de los requisitos más irritantes es el texto debajo de la línea. No se preocupe, aquí está la solución.
Subrayando un texto en un UILabel usando Objective C
UILabel *label=[[UILabel alloc]initWithFrame:CGRectMake(0, 0, 320, 480)]; label.backgroundColor=[UIColor lightGrayColor]; NSMutableAttributedString *attributedString; attributedString = [[NSMutableAttributedString alloc] initWithString:@"Apply Underlining"]; [attributedString addAttribute:NSUnderlineStyleAttributeName value:@1 range:NSMakeRange(0, [attributedString length])]; [label setAttributedText:attributedString];
Subrayar un texto en UILabel usando Swift
label.backgroundColor = .lightGray let attributedString = NSMutableAttributedString.init(string: "Apply UnderLining") attributedString.addAttribute(NSUnderlineStyleAttributeName, value: 1, range: NSRange.init(location: 0, length: attributedString.length)) label.attributedText = attributedString
fuente
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
fuente
He creado para uilabel multilínea con subrayado:
Para el tamaño de fuente de 8 a 13, establezca int lineHeight = self.font.pointSize + 3;
Para tamaños de fuente de 14 a 20, establezca 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]; }
fuente
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 alrededor del texto. Es posible que un cuadro con una altura de 50 y un tamaño de fuente de 12 no proporcione los resultados que desea según la configuración de UILabel.
Consulte el UIString dentro de UILabel para determinar sus métricas exactas y utilícelas para colocar mejor su subrayado, independientemente del cuadro delimitador o marco adjunto, utilizando el código de dibujo ya proporcionado por kovpas.
También debe observar la propiedad "principal" de UIFont que proporciona la distancia entre líneas de base según una fuente en particular. La línea de base es donde le gustarí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.
fuente
Utilizo una vista de línea de código abierto y simplemente la agregué a las subvistas de 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.
fuente
Basado en las respuestas de Kovpas y Damien Praca, aquí hay una implementación de UILabelUnderligned que también es compatible con textAlignemnt .
#import <UIKit/UIKit.h> @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
fuente
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 una UIView
(_view_underline)
que tiene un fondo blanco, una 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]; }
fuente
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];
fuente
Swift 4.1 versión:
let underlineAttriString = NSAttributedString(string:"attriString", attributes: [NSAttributedStringKey.underlineStyle: NSUnderlineStyle.styleSingle.rawValue]) label.attributedText = underlineAttriString
fuente
¡Puedes usar esta mi etiqueta personalizada! También puede utilizar el generador de interfaces para configurar
import UIKit class YHYAttributedLabel : UILabel{ @IBInspectable var underlineText : String = ""{ didSet{ self.attributedText = NSAttributedString(string: underlineText, attributes: [NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue]) } } }
fuente