Jak mogę podkreślić tekst, który może składać się z wielu wierszy ciągu? Uważam, że niektórzy sugerują UIWebView, ale jest to oczywiście zbyt ciężka klasa do renderowania tylko tekstu.
Myślałem, że chciałem ustalić punkt początkowy i długość każdej struny w każdej linii. I odpowiednio narysuj pod nim linię.
Spotykam się z problemami, jak obliczyć długość i punkt początkowy struny.
Próbowałem użyć -[UILabel textRectForBounds:limitedToNumberOfLines:]
, to powinien być prostokąt ograniczający rysunek dla tekstu, prawda? Więc muszę popracować nad wyrównaniem? Jak mogę uzyskać punkt początkowy każdej linii, gdy jest wyjustowany do środka i do prawej?
Odpowiedzi:
Możesz podklasować z UILabel i nadpisać metodę 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:
Od iOS 6 Apple dodał obsługę NSAttributedString dla UILabel, więc teraz jest to znacznie łatwiejsze i działa dla wielu linii:
NSDictionary *underlineAttribute = @{NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle)}; myLabel.attributedText = [[NSAttributedString alloc] initWithString:@"Test string" attributes:underlineAttribute];
Jeśli nadal chcesz obsługiwać iOS 4 i iOS 5, polecam użycie TTTAttributedLabel zamiast ręcznego podkreślania etykiety. Jeśli jednak chcesz podkreślić jednowierszowy UILabel i nie chcesz używać komponentów innych firm, powyższy kod nadal by załatwił sprawę.
źródło
W Swift:
let underlineAttriString = NSAttributedString(string: "attriString", attributes: [NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue]) label.attributedText = underlineAttriString
źródło
To właśnie zrobiłem. Działa jak masło.
1) Dodaj CoreText.framework do swoich frameworków.
2) zaimportuj <CoreText / CoreText.h> do klasy, w której potrzebujesz podkreślonej etykiety.
3) Napisz następujący kod.
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];
źródło
Użyj ciągu atrybutu:
NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] initWithString:@"Your String"] [attrString addAttribute:(NSString*)kCTUnderlineStyleAttributeName value:[NSNumber numberWithInt:kCTUnderlineStyleSingle] range:(NSRange){0,[attrString length]}];
A następnie nadpisz etykietę - (void) drawTextInRect: (CGRect) aRect i wyrenderuj tekst na coś takiego:
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);
Albo jeszcze lepiej, zamiast nadpisywać, po prostu użyj OHAttributedLabel stworzonej przez Oliviera Halligona
źródło
NSMutableAttributedString
Połączyłem niektóre z udzielonych odpowiedzi, aby stworzyć lepszą (przynajmniej jak na moje wymagania) podklasę UILabel, która obsługuje:
https://github.com/GuntisTreulands/UnderLineLabel
źródło
Osoby, które nie chcą tworzyć podklasy widoku (UILabel / UIButton) itp. ... „ForgetButton” mogą również zostać zastąpione przez dowolną etykietę.
-(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]; }
źródło
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; }
źródło
Innym rozwiązaniem może być (od iOS 7) nadanie wartości ujemnej
NSBaselineOffsetAttributeName
, na przykładNSAttributedString
:NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:@"my text goes here' attributes:@{NSFontAttributeName: [UIFont fontWithName:@"Helvetica-Regular" size:12], NSForegroundColorAttributeName: [UIColor blackColor], NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle), NSBaselineOffsetAttributeName: @(-3)}];
Mam nadzieję, że to pomoże ;-)
źródło
NSMutableAttributedString *text = [self.myUILabel.attributedText mutableCopy]; [text addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:NSMakeRange(0, text.length)]; self.myUILabel.attributedText = text;
źródło
Możesz stworzyć własną etykietę o nazwie UnderlinedLabel i edytować funkcję 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]; }
źródło
Oto najłatwiejsze rozwiązanie, które działa u mnie bez pisania dodatkowych kodów.
// 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;
źródło
Czasami deweloperzy utknęli w małej części projektowej dowolnego ekranu interfejsu użytkownika. Jednym z najbardziej irytujących wymagań jest tekst pod linią. Nie martw się, tutaj jest rozwiązanie.
Podkreślenie tekstu w UILabel przy użyciu celu 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];
Podkreślanie tekstu w UILabel za pomocą 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
źródło
Ulepszona wersja kodu Kovpas (kolor i rozmiar linii)
@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
źródło
Stworzyłem dla wielowierszowego uilabel z podkreśleniem:
Dla rozmiaru czcionki od 8 do 13 ustaw int lineHeight = self.font.pointSize + 3;
Dla rozmiaru czcionki od 14 do 20 ustaw 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]; }
źródło
Jak pokazał kovpas, w większości przypadków możesz użyć obwiedni, chociaż nie zawsze jest gwarantowane, że obwiednia będzie dokładnie dopasowana do tekstu. Ramka o wysokości 50 i rozmiarze czcionki 12 może nie dawać oczekiwanych wyników w zależności od konfiguracji UILabel.
Zapytaj o UIString w UILabel, aby określić jego dokładne metryki i użyj ich do lepszego umieszczenia podkreślenia niezależnie od otaczającej ramki ograniczającej lub ramki, używając kodu rysunkowego już dostarczonego przez kovpas.
Powinieneś także przyjrzeć się właściwości „wiodącej” UIFont, która podaje odległość między liniami bazowymi w oparciu o określoną czcionkę. Linia bazowa to miejsce, w którym chcesz narysować podkreślenie.
Wyszukaj dodatki UIKit do 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.
źródło
Używam widoku liniowego typu open source i właśnie dodałem go do podglądów przycisków:
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];
To było zainspirowane przez Karima powyżej.
źródło
W oparciu o odpowiedzi Kovpasa i Damiena Praca, oto implementacja UILabelUnderligned, która obsługuje również textAlignemnt .
#import <UIKit/UIKit.h> @interface UILabelUnderlined : UILabel @end
i realizacja:
#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
źródło
Oto inne, prostsze rozwiązanie (szerokość podkreślenia nie jest najdokładniejsza, ale dla mnie wystarczyła)
Mam UIView,
(_view_underline)
który ma białe tło, wysokość 1 piksela i aktualizuję jego szerokość za każdym razem, gdy aktualizuję tekst// 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]; }
źródło
NSUnderlineStyleAttributeName, który przyjmuje numer NSNumber (gdzie 0 nie jest podkreśleniem), można dodać do słownika atrybutów. Nie wiem, czy to jest łatwiejsze. Ale dla moich celów było to łatwiejsze.
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];
źródło
Wersja Swift 4.1:
let underlineAttriString = NSAttributedString(string:"attriString", attributes: [NSAttributedStringKey.underlineStyle: NSUnderlineStyle.styleSingle.rawValue]) label.attributedText = underlineAttriString
źródło
Możesz użyć tej mojej niestandardowej etykiety! Do ustawienia możesz również użyć konstruktora interfejsu
import UIKit class YHYAttributedLabel : UILabel{ @IBInspectable var underlineText : String = ""{ didSet{ self.attributedText = NSAttributedString(string: underlineText, attributes: [NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue]) } } }
źródło