在UIlabel下划线文本


89

如何在可能是多行字符串的文本下划线?我发现有人建议使用UIWebView,但是对于仅用于文本呈现的类来说,它显然太重了。

我的想法是弄清楚每行中每个字符串的起点和长度。并在其下画一条线。

我在如何计算字符串的长度和起始点时遇到问题。

我尝试使用-[UILabel textRectForBounds:limitedToNumberOfLines:],这应该是文本的图形边界矩形吗?那我必须进行对齐吗?当中心对齐并右对齐时,如何获得每条线的起点?


Answers:


137

您可以从UILabel继承子类,并重写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:
从iOS 6开始,Apple为UILabel添加了NSAttributedString支持,因此现在它变得更加简单并且可以用于多行:

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

如果您仍然希望支持iOS 4和iOS 5,建议您使用TTTAttributedLabel,而不要手动添加下划线标签。但是,如果您需要在单行UILabel下划线,并且不想使用第三方组件,则上面的代码仍然可以解决问题。


3
我想这只会在字符串的最后一行画一个下划线,对吗?在其他行中该字符串的下划线呢?
semix

2
它不会做多行,但这是我能找到的最好的,所以我想多行是不可能的。我想我能想到的下一个最佳解决方案是导入在字体中内置下划线的字体。这仅适用于可以导入字体的ios 4.0+。
DonnaLea 2011年

嗨,我想知道这是否违反任何ios ui标准。
thndrkiss

苹果的实现(第二个建议)不支持该行以下的字符?screencast.com/t/NGvQJqoWAD3J
pfrank

如果我们对UILabel使用NSAttributedString支持,则对于g,p和q之类的字母,下划线将被截断。有人面对这个问题吗?示例:登录
dev4u 2014年

46

在Swift中:

let underlineAttriString = NSAttributedString(string: "attriString",
                                          attributes: [NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue])
label.attributedText = underlineAttriString

在Swift 3中,您唯一要做的就是将.StyleSingle更改为.styleSingle,它在Swift3中是驼峰式的,但是很好的答案!
乔什·奥康纳

如果没有.rawValue,这将导致我崩溃。
jackofallcode

您只需要.rawValue即可快速获得4.0版本
胡萝卜糖

太冗长而无法画底线。
khcpietro

38

这就是我所做的。它像黄油一样工作。

1)将CoreText.framework添加到您的框架中。

2)在需要下划线标签的类中导入<CoreText / CoreText.h>。

3)编写以下代码。

    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];

请给我+1,因为它的确非常出色,并且它演示了设置特定字符范围的简便方法(这正是我需要的)。谢谢!-Erik
Erik van der Neut 2015年

19

使用属性字符串:

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

然后覆盖标签-(void)drawTextInRect:(CGRect)aRect并以类似以下方式呈现文本:

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);

或更好的方法是使用Olivier Halligon创建的OHAttributedLabel而不是覆盖


1
最上面一行应该是NSMutableAttributedString
borrrden'5

我使用OHAttributedLabel删除的原因是-至少对我来说,无法计算准确的文本高度。在10%的情况下,它是不正确的。(也许是因为我使用了不同的字体。)
Guntis Treulands 2012年


11

不想将视图子类化(UILabel / UIButton)等的人...'forgetButton'也可以用任何标签代替。

-(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];
}

2
-1用于调用“ draw…”,该方法分配UILabel并将其添加到视图中。
jcayzac 2012年

1
我已经对其进行了修改,使其更加通用:pastebin.com/QkF9ifpb原始文件无法说明标签是否在子视图中。
Fonix

8
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;
}

7

另一个解决方案可能是(自iOS 7起)为赋予负值NSBaselineOffsetAttributeName,例如,您NSAttributedString可以是:

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

希望这会有所帮助;-)


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

3

您可以创建名称为UnderlinedLabel的自定义标签并编辑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];
}

3

这是最简单的解决方案,无需编写其他代码即可对我有效。

// 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;

3

有时,我们开发人员陷入了任何UI屏幕的小型设计部分中。最令人讨厌的要求之一是在行文本下。不用担心,这是解决方案。

在此处输入图片说明

使用Objective C在UILabel中给文本加下划线

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];

使用Swift在UILabel中给文本加下划线

 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

1

Kovpas代码的增强版本(颜色和行大小)

@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

1

我已经为带有下划线的多行uilabel创建了:

对于8至13的字体,设置int lineHeight = self.font.pointSize + 3;

对于14到20的字体,设置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]; 
}

0

如kovpas所示,尽管并非总是保证边界框可以整齐地围绕文本,但在大多数情况下都可以使用边界框。高度为50且字体大小为12的框可能无法提供所需的结果,具体取决于UILabel配置。

在UILabel中查询UIString以确定其确切的度量标准,并使用这些参数更好地放置下划线,而不必使用kovpas已经提供的绘图代码来包围边框或框架。

您还应该查看UIFont的“前导”属性,该属性根据特定字体给出基线之间的距离。基线是您希望绘制下划线的位置。

查找UIKit对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.

肯尼(Kenny),看来我可以使用3种方法轻松获得文本第一行的宽度,但是第二,第三行和其他行呢?你能给我举个例子吗?
semix

我必须承认。现在,有一种使用NSString来实现所需功能的方法,除非其他人可以提供更多的功能。我将不得不像其他人一样建议使用UIWebView并将您的文本填充到视图中:[webView loadHTMLString:@“ <html> <u>带下划线的文本。</ u> </ html>” baseURL:nil ]; 让它进行布局并确定线的位置。如果是您要在第n行加上下划线并且您不知道哪一条是第n行,那么这是另一回事。
gnasher 2010年

0

我使用开放源代码行视图,并将其添加到按钮子视图中:

 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];

这是受到上面Karim的启发的。


您可以只使用UIVIew。UIView * line = [[UIView alloc] initWithFrame:frame]; line.backgroundColor = [UIColor lightGrayColor];
dzeikei 2012年

0

基于Kovpas和Damien Praca的答案,这是UILabelUnderligned的实现,该实现也支持textAlignemnt

#import <UIKit/UIKit.h>

@interface UILabelUnderlined : UILabel

@end

和实现:

#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

适用于iOS 6的开关的更新:开关(self.textAlignment){case NSTextAlignmentLeft:case NSTextAlignmentJustified:case NSTextAlignmentNatural:break; 案例NSTextAlignmentCenter:alignementXOffset =(self.titleLabel.frame.size.width-textSize.width)/ 2; 打破; case NSTextAlignmentRight:alignementXOffset = self.titleLabel.frame.size.width-textSize.width; 打破; }
pfrank

0

这是另一个更简单的解决方案(下划线的宽度不是最准确,但是对我来说足够了)

我有一个UIView (_view_underline),背景为白色,高度为1像素,每次更新文本时都会更新其宽度

// 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];
}

0

可以将带有NSNumber(其中0不为下划线)的NSUnderlineStyleAttributeName添加到属性字典中。我不知道这是否更容易。但是,对我而言,这更容易。

    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];

0

Swift 4.1版本:

 let underlineAttriString = NSAttributedString(string:"attriString", attributes:
    [NSAttributedStringKey.underlineStyle: NSUnderlineStyle.styleSingle.rawValue])

label.attributedText = underlineAttriString

0

您可以使用我的自定义标签!您也可以使用界面构建器进行设置

import UIKit


class  YHYAttributedLabel : UILabel{
    
    
    @IBInspectable
    var underlineText : String = ""{
        
        didSet{

            self.attributedText = NSAttributedString(string: underlineText,
            attributes: [NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue])
        }
        
        
    }

}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.