Como posso sublinhar um texto que pode ter várias linhas de string? Acho que algumas pessoas sugerem UIWebView, mas obviamente é uma classe muito pesada para apenas renderização de texto.
Meu pensamento era descobrir o ponto inicial e o comprimento de cada corda em cada linha. E desenhe uma linha em conformidade
Encontro problemas em como descobrir o comprimento e o ponto inicial da corda.
Tentei usar -[UILabel textRectForBounds:limitedToNumberOfLines:]
, este deve ser o retângulo delimitador do desenho certo? Então eu tenho que trabalhar no alinhamento? Como posso obter o ponto inicial de cada linha quando ela está justificada ao centro e à direita?
Respostas:
Você pode criar uma subclasse de UILabel e substituir o 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 do iOS 6, a Apple adicionou suporte a NSAttributedString para UILabel, então agora é muito mais fácil e funciona para várias linhas:
NSDictionary *underlineAttribute = @{NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle)}; myLabel.attributedText = [[NSAttributedString alloc] initWithString:@"Test string" attributes:underlineAttribute];
Se você ainda deseja oferecer suporte ao iOS 4 e iOS 5, recomendo usar TTTAttributedLabel em vez de sublinhar o rótulo manualmente. No entanto, se você precisar sublinhar UILabel de uma linha e não quiser usar componentes de terceiros, o código acima ainda resolverá o problema.
fonte
Em Swift:
let underlineAttriString = NSAttributedString(string: "attriString", attributes: [NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue]) label.attributedText = underlineAttriString
fonte
Isso é o que eu fiz. Funciona como manteiga.
1) Adicione CoreText.framework aos seus Frameworks.
2) importe <CoreText / CoreText.h> na classe onde você precisa do rótulo sublinhado.
3) Escreva o seguinte 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];
fonte
Use uma string de atributo:
NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] initWithString:@"Your String"] [attrString addAttribute:(NSString*)kCTUnderlineStyleAttributeName value:[NSNumber numberWithInt:kCTUnderlineStyleSingle] range:(NSRange){0,[attrString length]}];
Em seguida, substitua o rótulo - (void) drawTextInRect: (CGRect) aRect e renderize o texto em 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);
Ou melhor ainda, em vez de substituir, basta usar o OHAttributedLabel criado por Olivier Halligon
fonte
NSMutableAttributedString
Combinei algumas das respostas fornecidas para criar uma subclasse UILabel melhor (pelo menos para os meus requisitos), que suporta:
https://github.com/GuntisTreulands/UnderLineLabel
fonte
Pessoas que não querem uma subclasse da visão (UILabel / UIButton) etc ... 'forgetButton' pode ser substituído por qualquer lable também.
-(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]; }
fonte
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; }
fonte
Outra solução poderia ser (desde iOS 7) dado um valor negativo para
NSBaselineOffsetAttributeName
, por exemplo, seuNSAttributedString
poderia 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 isso ajude ;-)
fonte
NSMutableAttributedString *text = [self.myUILabel.attributedText mutableCopy]; [text addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:NSMakeRange(0, text.length)]; self.myUILabel.attributedText = text;
fonte
Você pode criar um rótulo personalizado com o nome UnderlinedLabel e editar a função 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]; }
fonte
Aqui está a solução mais fácil que funciona para mim sem escrever códigos adicionais.
// 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;
fonte
Às vezes, nós desenvolvedores ficamos presos em uma pequena parte de design de qualquer tela da IU. Um dos requisitos mais irritantes é o texto de linha. Não se preocupe, aqui está a solução.
Sublinhando um texto em um 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];
Sublinhando um texto em 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
fonte
Uma versão aprimorada do código de Kovpas (cor e tamanho da linha)
@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
fonte
Eu criei para uilabel multilinha com sublinhado:
Para tamanho de fonte 8 a 13, defina int lineHeight = self.font.pointSize + 3;
Para o tamanho da fonte de 14 a 20, defina 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]; }
fonte
Como kovpas mostrou, você pode usar a caixa delimitadora na maioria dos casos, embora nem sempre seja garantido que a caixa delimitadora se encaixará perfeitamente ao redor do texto. Uma caixa com uma altura de 50 e tamanho de fonte de 12 pode não dar os resultados desejados dependendo da configuração do UILabel.
Consulte o UIString dentro do UILabel para determinar suas métricas exatas e use-as para posicionar melhor o seu sublinhado, independentemente da caixa delimitadora ou do quadro envolvente, usando o código de desenho já fornecido por kovpas.
Você também deve observar a propriedade "principal" do UIFont, que fornece a distância entre as linhas de base com base em uma fonte específica. A linha de base é onde você deseja que seu sublinhado seja desenhado.
Procure as adições 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.
fonte
Eu uso uma visualização de linha de código aberto e acabei de adicioná-la às subvisualizações do botão:
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];
Isso foi inspirado por Karim acima.
fonte
Com base nas respostas de Kovpas e Damien Praca, aqui está uma implementação de UILabelUnderligned que também oferece suporte a textAlignemnt .
#import <UIKit/UIKit.h> @interface UILabelUnderlined : UILabel @end
e a implementação:
#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
fonte
Aqui está outra solução mais simples (a largura do sublinhado não é a mais precisa, mas foi boa o suficiente para mim)
Eu tenho um UIView
(_view_underline)
que tem fundo branco, altura de 1 pixel e eu atualizo sua largura toda vez que atualizo o 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]; }
fonte
NSUnderlineStyleAttributeName que leva um NSNumber (onde 0 é nenhum sublinhado) pode ser adicionado a um dicionário de atributos. Não sei se isso é mais fácil. Mas, era mais fácil para meus 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];
fonte
Swift 4.1 versão:
let underlineAttriString = NSAttributedString(string:"attriString", attributes: [NSAttributedStringKey.underlineStyle: NSUnderlineStyle.styleSingle.rawValue]) label.attributedText = underlineAttriString
fonte
Você pode usar este meu rótulo personalizado! Você também pode usar o construtor de interface para definir
import UIKit class YHYAttributedLabel : UILabel{ @IBInspectable var underlineText : String = ""{ didSet{ self.attributedText = NSAttributedString(string: underlineText, attributes: [NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue]) } } }
fonte