Підкресліть текст у 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

привіт, я хочу знати, чи не порушує це будь-який із стандартів ios ui.
thndrkiss

Реалізація Apple (друга пропозиція) не підтримує символи, які йдуть нижче рядка? screencast.com/t/NGvQJqoWAD3J
pfrank

Якщо ми використовуємо підтримку NSAttributedString для UILabel, для таких алфавітів, як g, підкреслення p & q є усіченням. Хтось стикався з проблемою? Приклад: Логін
dev4u

46

Свіфт:

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

Єдине, що вам потрібно зробити в Swift 3, це змінити .StyleSingle на .styleSingle, це CamelCased в Swift3, але чудова відповідь!
Джош О'Коннор,

Без .rawValue це спричинило для мене збій.
jackofallcode

вам знадобиться лише .rawValue для swift 4.0
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];

+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% випадків це було неправильно. (можливо, тому, що я використовував інший шрифт ..)
Guntis Treulands

15

Я об’єднав деякі надані відповіді, щоб створити кращий (принаймні для моїх вимог) підклас UILabel, який підтримує:

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

https://github.com/GuntisTreulands/UnderLineLabel


11

Людей, які не хочуть підкласувати подання (UILabel / UIButton) і т. Д. 'ЗабутиКнопку' також можна замінити будь-якою міткою.

-(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 для виклику методу "намалювати ...", який виділяє UILabel і додає його до подання.
jcayzac

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

Іноді ми, розробник, застрягли в невеликій частині дизайну будь-якого екрана інтерфейсу користувача. Однією з найбільш дратуючих вимог є текст рядка. Не хвилюйтеся, ось рішення.

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

Підкреслення тексту в UILabel за допомогою Цілі 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

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

Запитуйте UIString всередині UILabel, щоб визначити його точні метрики, і використовуйте їх, щоб краще розмістити підкреслення, незалежно від вкладеного обмежувального поля або кадру, використовуючи код креслення, вже наданий 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.

Кенні, здається, я можу використовувати 3 методи, щоб легко отримати ширину 1-го рядка тексту, але як щодо 2-го 3-го та інших рядків? Можете навести приклад?
semix

Я повинен поступитися. Зараз є спосіб використовувати NSString для досягнення того, що ви хочете, якщо хтось інший не може запропонувати більше. Мені доведеться запропонувати, як і інші до мене, використовувати UIWebView та вставити ваш текст у подання: [webView loadHTMLString: @ "<html> <u> Підкреслений текст. </u> </html>" baseURL: nil ]; Нехай це робить макет і визначає, куди повинні йти лінії. Якщо справа в тому, що ви хочете підкреслити n-й рядок, і ви не можете знати, який це n-й рядок, це інша справа.
гранатор

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 * рядок = [[UIView alloc] initWithFrame: кадр]; line.backgroundColor = [UIColor lightGrayColor];
dzeikei

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; case NSTextAlignmentCenter: alignementXOffset = (self.titleLabel.frame.size.width - textSize.width) / 2; перерву; регістр 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

Свіфт 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])
        }
        
        
    }

}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.