在UIlabel中下划线文本

94

如何为可能跨越多行的文本添加下划线呢?

有些人建议使用UIWebView,但仅用于文本渲染显然太重了。

我的想法是找出每行每个字符串的起始点和长度,并相应地在下面画一条线。

我遇到的问题是如何找出字符串的长度和起始点。

我尝试使用-[UILabel textRectForBounds:limitedToNumberOfLines:],这应该是文本的绘制边界矩形,对吗? 然后我还需要处理对齐方式? 当它居中对齐和右对齐时,如何获取每行字符串的起始点?


1
看看这篇博客文章 - Casebash
21个回答

138

你可以从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];  
}

更新:
自iOS 6起,苹果公司为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
嗨,我想知道这是否违反了任何 iOS UI 标准。 - thndrkiss
苹果的实现(第二个建议)不支持低于基线的字符?http://screencast.com/t/NGvQJqoWAD3J - pfrank
如果我们在UILabel中使用NSAttributedString支持,对于像g、p和q这样的字母,下划线会被截断。有人遇到过这个问题吗? 示例:登录 - dev4u

58

在Swift中:

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

在Swift 3中,你唯一需要做的就是将.StyleSingle更改为.styleSingle,它在Swift3中采用驼峰式大小写,但回答很好! - Josh O'Connor
没有使用.rawValue,这导致了我的程序崩溃。 - jackofallcode
在Swift 4.0中,您只需要使用.rawValue。 - carrotzoe
太啰嗦了,只是画下划线而已。 - 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];

我对这个答案点赞,因为它确实非常出色,并且演示了一种设置特定字符范围的简单方法(这也是我自己所需要的)。谢谢!-- Erik - Erik van der Neut

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
我放弃使用OHAttributedLabel的原因是,至少对我来说,无法计算准确的文本高度。在10%的情况下,它是不正确的。(也许是因为我使用了不同的字体..) - Guntis Treulands

15

我结合了提供的一些答案,创建了一个更好的(至少对我的要求来说更好)UILabel子类,支持以下功能:

  • 多行文本与各种标签边界 (文本可以在标签框的中间或准确的大小)
  • 下划线
  • 删除线
  • 下划线/删除线偏移量
  • 文本对齐
  • 不同的字体大小

https://github.com/GuntisTreulands/UnderLineLabel


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
调用“draw…”方法会分配一个UILabel并将其添加到视图中,这是不推荐的。 - jcayzac
1
我已经将其改为更通用的形式:http://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];
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接