ขีดเส้นใต้ข้อความใน UIlabel


89

ฉันจะขีดเส้นใต้ข้อความที่อาจเป็นสตริงหลายบรรทัดได้อย่างไร ฉันพบว่ามีบางคนแนะนำ UIWebView แต่เห็นได้ชัดว่าเป็นคลาสที่หนักเกินไปสำหรับการแสดงผลข้อความ

ความคิดของฉันคือการหาจุดเริ่มต้นและความยาวของแต่ละสตริงในแต่ละบรรทัด แล้วลากเส้นใต้ตามนั้น

ฉันพบปัญหาเกี่ยวกับวิธีการหาความยาวและจุดเริ่มต้นของสตริง

ฉันพยายามใช้-[UILabel textRectForBounds:limitedToNumberOfLines:]นี่ควรจะเป็นรูปสี่เหลี่ยมผืนผ้าที่มีขอบเขตสำหรับข้อความใช่ไหม แล้วฉันต้องทำงานในการจัดตำแหน่ง? ฉันจะได้รับจุดเริ่มต้นของแต่ละบรรทัดได้อย่างไรเมื่อมันอยู่ตรงกลางและถูกต้อง


คำตอบ:


137

คุณสามารถ subclass จาก 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
— เล่นพิเรน

หากเราใช้การสนับสนุน NSAttributedString สำหรับ UILabel สำหรับตัวอักษรเช่น g, p & q ขีดเส้นใต้จะถูกตัดทอน มีใครประสบปัญหา? ตัวอย่าง: เข้าสู่ระบบ
— dev4u

46

ใน Swift:

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

สิ่งเดียวที่คุณต้องทำใน Swift 3 คือการเปลี่ยนแปลง StyleSingle เป็น. styleSingle คือ camelCased ใน Swift3 แต่ตอบโจทย์มาก!
— Josh O'Connor

หากไม่มี .rawValue สิ่งนี้ทำให้ฉันขัดข้อง
— jackofallcode

คุณต้องการเพียง .rawValue สำหรับ swift 4.0
— carrotzoe

ละเอียดเกินไปที่จะขีดเส้นใต้
— khcpietro

38

นี่คือสิ่งที่ฉันทำ มันทำงานเหมือนเนย

1) เพิ่ม CoreText.framework ใน Frameworks ของคุณ

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

19

ใช้สตริงแอตทริบิวต์:

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

จากนั้นแทนที่เลเบล - (โมฆะ) 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 ที่สร้างโดย Olivier Halligon


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
-1 สำหรับการเรียก "วาด ... " วิธีที่จัดสรร 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)}];

หวังว่านี่จะช่วยได้ ;-)


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 ใด ๆ ข้อกำหนดที่น่ารำคาญที่สุดประการหนึ่งคือใต้ข้อความบรรทัด ไม่ต้องกังวลนี่คือทางออก

ป้อนคำอธิบายภาพที่นี่

การขีดเส้นใต้ข้อความใน 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

รหัสรุ่นปรับปรุงของ 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 หลายบรรทัดพร้อมขีดเส้นใต้:

สำหรับ Font ขนาด 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.

Kenny ดูเหมือนว่าฉันสามารถใช้ 3 วิธีเพื่อรับความกว้างของบรรทัดที่ 1 ได้อย่างง่ายดาย แต่บรรทัดที่ 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];

สิ่งนี้ได้รับแรงบันดาลใจจาก Karim ด้านบน


คุณสามารถใช้ UIVIew UIView * line = [[UIView จัดสรร] initWithFrame: frame]; line.backgroundColor = [UIColor lightGrayColor];
— dzeikei

0

ขึ้นอยู่กับคำตอบ Kovpas และดาเมียน 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; หยุดพัก; กรณี NSTextAlignmentRight: alignementXOffset = self.titleLabel.frame.size.width - textSize.width; หยุดพัก; }
— เล่นพิเรน

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

0

คุณสามารถใช้ป้ายที่กำหนดเองของฉันได้! คุณยังสามารถใช้ตัวสร้างอินเทอร์เฟซเพื่อตั้งค่า

import UIKit


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

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

}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.