Подчеркнуть текст в UIlabel

89

Как я могу подчеркнуть текст, который может состоять из нескольких строк? Я считаю, что некоторые люди предлагают UIWebView, но это явно слишком тяжелый класс для простого рендеринга текста.

Я думал о том, чтобы выяснить начальную точку и длину каждой строки в каждой строке. И соответственно проведите под ним линию.

У меня возникают проблемы с тем, как определить длину и начальную точку строки.

Я пытался использовать -[UILabel textRectForBounds:limitedToNumberOfLines:], это должен быть ограничивающий прямоугольник для текста, верно? Тогда мне нужно работать над выравниванием? Как я могу получить начальную точку каждой линии, если она выровнена по центру и по правому краю?

полумикс
источник
1
Посмотрите этот пост в блоге
Casebash

Ответы:

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 добавила поддержку NSAttributedString для UILabel, поэтому теперь это намного проще и работает для нескольких строк:

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 08
привет, я хочу знать, нарушает ли это какой-либо из стандартов пользовательского интерфейса iOS.
thndrkiss 02
Реализация Apple (второе предложение) не поддерживает символы, идущие ниже линии? screencast.com/t/NGvQJqoWAD3J
pfrank
Если мы используем поддержку NSAttributedString для UILabel, для таких алфавитов, как g, p и q, подчеркивание будет усечено. Кто-нибудь сталкивается с проблемой? Пример: Логин
dev4u
46

В Swift:

let underlineAttriString = NSAttributedString(string: "attriString",
                                          attributes: [NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue])
label.attributedText = underlineAttriString
ytll21
источник
Единственное, что вам нужно сделать в Swift 3, - это изменить .StyleSingle на .styleSingle, это camelCased в Swift3, но отличный ответ!
Джош О'Коннор
Без .rawValue это вызывало у меня сбой.
jackofallcode
вам понадобится только .rawValue для swift 4.0
carrotzoe 08
Слишком многословен, чтобы просто подчеркивать.
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 от меня за этот ответ, потому что это действительно блестяще работает, и он демонстрирует простой способ установить определенный диапазон символов (это то, что мне самому было нужно). Благодарность! - Эрик
Эрик ван дер Нейт
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);

Или еще лучше вместо переопределения просто используйте OHAttributedLabel, созданный Оливье Халлигоном.

Пауло Феррейра
источник
1
Верхняя строчка должна бытьNSMutableAttributedString
borrrden
Причина, по которой я отказался от использования OHAttributedLabel, заключалась в том, что, по крайней мере, для меня было невозможно вычислить точную высоту текста. в 10% случаев это было неверно. (может быть, потому что я использовал другой шрифт ..)
Гунтис Треуландс
15

Я объединил некоторые из предоставленных ответов, чтобы создать лучший (по крайней мере, для моих требований) подкласс UILabel, который поддерживает:

  • многострочный текст с различными границами метки (текст может быть в середине рамки метки или точного размера)
  • подчеркивать
  • зачеркнутый
  • смещение подчеркивания / зачеркивания
  • выравнивание текста
  • разные размеры шрифта

https://github.com/GuntisTreulands/UnderLineLabel

Гунтис Треуландс
источник
11

Людям, которые не хотят создавать подклассы представления (UILabel / UIButton) и т. Д., "ЗабудьтеButton" также можно заменить любой меткой.

-(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
1
Я адаптировал это, чтобы сделать его более общим: pastebin.com/QkF9ifpb original не учитывает, находится ли метка в подпредставлении.
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)}];

Надеюсь, это поможет ;-)

Youssman
источник
7
NSMutableAttributedString *text = [self.myUILabel.attributedText mutableCopy];
[text addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:NSMakeRange(0, text.length)];
self.myUILabel.attributedText = text;
Роман Солодяшкин
источник
3

Вы можете создать собственный ярлык с именем UnderlineLabel и отредактировать функцию 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];
}
nfinfu
источник
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

Иногда мы, разработчики, застреваем в небольшой части дизайна любого экрана пользовательского интерфейса. Одно из самых раздражающих требований - текст под строкой. Не волнуйтесь, вот решение.

введите описание изображения здесь

Подчеркивание текста в UILabel с помощью 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];

Подчеркивание текста в UILabel с использованием 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
Г-н Джавед Мултани
источник
1

Расширенная версия кода Ковпаса (цвет и размер линии)

@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

Как показал Ковпас, вы можете использовать ограничивающую рамку в большинстве случаев, хотя не всегда гарантируется, что ограничивающая рамка будет аккуратно вписываться в текст. Поле с высотой 50 и размером шрифта 12 может не дать желаемых результатов в зависимости от конфигурации UILabel.

Запросите UIString в UILabel, чтобы определить его точные метрики, и используйте их, чтобы лучше разместить подчеркивание независимо от ограничивающей рамки или рамки, используя код рисования, уже предоставленный kovpas.

Вам также следует обратить внимание на свойство UIFont "lead", которое определяет расстояние между базовыми линиями на основе определенного шрифта. Базовая линия - это то место, где вы хотите нарисовать подчеркивание.

Посмотрите дополнения 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.
скряга
источник
Кенни, кажется, я могу использовать 3 метода, чтобы легко получить ширину первой строки текста, но как насчет второй, третьей и других строк? Вы можете привести пример?
semix
Я должен уступить. Теперь есть способ использовать NSString для достижения того, чего вы хотите, если только кто-то другой не может предложить больше. Я собираюсь предложить, как и другие до меня, использовать UIWebView и поместить ваш текст в представление: [webView loadHTMLString: @ "<html> <u> подчеркнутый текст. </u> </html>" baseURL: nil ]; Пусть он сделает разметку и определит, где должны идти линии. Если вы хотите, чтобы n-я строка была подчеркнута, и вы не можете знать, какая именно n-я строка, это другое дело.
gnasher
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];

Это было вдохновлено Каримом выше.

Дэвид Х
источник
Вы можете просто использовать UIVIew. UIView * line = [[UIView alloc] initWithFrame: frame]; line.backgroundColor = [UIColor lightGrayColor];
dzeikei 01
0

Основываясь на ответах Ковпаса и Дэмиена Прака, вот реализация 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 для коммутатора: switch (self.textAlignment) {case NSTextAlignmentLeft: case NSTextAlignmentJustified: case NSTextAlignmentNatural: break; case 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

NSUnderlineStyleAttributeName, который принимает NSNumber (где 0 - без подчеркивания), может быть добавлен в словарь атрибутов. Не знаю, проще ли это. Но для моих целей это было проще.

    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
Abdoelrhman
источник
0

Вы можете использовать этот мой собственный ярлык! Вы также можете использовать построитель интерфейса, чтобы установить

import UIKit


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

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

}
Уддемир
источник