Garis bawahi teks di UIlabel

89

Bagaimana saya bisa menggarisbawahi teks yang bisa terdiri dari beberapa baris string? Saya menemukan beberapa orang menyarankan UIWebView, tetapi ini jelas merupakan kelas yang terlalu berat hanya untuk rendering teks.

Pikiranku adalah mencari tahu titik awal dan panjang setiap senar di setiap baris. Dan buat garis di bawahnya sesuai dengan itu.

Saya menemui masalah tentang cara mengetahui panjang dan titik awal untuk string.

Saya mencoba menggunakan -[UILabel textRectForBounds:limitedToNumberOfLines:], ini harus menjadi gambar pembatas persegi untuk teks kan? Lalu saya harus mengerjakan perataan? Bagaimana saya bisa mendapatkan titik awal setiap baris jika rata tengah dan rata kanan?

semix
sumber
1
Lihat posting blog ini
Casebash

Jawaban:

137

Anda dapat membuat subkelas dari UILabel dan mengganti metode 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:
Mulai iOS 6 Apple menambahkan dukungan NSAttributedString untuk UILabel, jadi sekarang jauh lebih mudah dan berfungsi untuk banyak baris:

NSDictionary *underlineAttribute = @{NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle)};
myLabel.attributedText = [[NSAttributedString alloc] initWithString:@"Test string" 
                                                         attributes:underlineAttribute];

Jika Anda masih ingin mendukung iOS 4 dan iOS 5, saya sarankan untuk menggunakan TTTAttributedLabel daripada label garis bawah secara manual. Namun jika Anda perlu menggarisbawahi satu baris UILabel dan tidak ingin menggunakan komponen pihak ketiga, kode di atas masih bisa digunakan.

kovpas.dll
sumber
3
Saya kira ini hanya akan menarik satu garis bawah untuk baris terakhir dari string, bukan? Bagaimana dengan garis bawah untuk string di baris lain?
semix
2
itu tidak melakukan banyak baris, tapi ini adalah yang terbaik yang bisa saya temukan, jadi saya kira banyak baris tidak mungkin. Saya kira solusi terbaik berikutnya yang dapat saya pikirkan adalah mengimpor font yang memiliki garis bawah di dalam font. Ini hanya akan berfungsi dari ios 4.0+ tempat Anda dapat mengimpor font.
DonnaLea
hai, saya ingin tahu apakah ini melanggar salah satu standar ios ui.
thndrkiss
Implementasi Apple (saran kedua) tidak mendukung karakter yang berada di bawah garis? screencast.com/t/NGvQJqoWAD3J
pfrank
Jika kami menggunakan dukungan NSAttributedString untuk UILabel, untuk alfabet seperti g, p & q, garis bawahi dipotong. Adakah yang menghadapi masalah ini? Contoh: Login
dev4u
46

Di Swift:

let underlineAttriString = NSAttributedString(string: "attriString",
                                          attributes: [NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue])
label.attributedText = underlineAttriString
ytll21
sumber
Satu-satunya hal yang harus Anda lakukan di Swift 3 adalah mengubah .StyleSingle menjadi .styleSingle, ini adalah camelCased di Swift3, tapi jawaban yang bagus!
Josh O'Connor
Tanpa .rawValue, ini menyebabkan error pada saya.
jackofallcode
Anda hanya perlu .rawValue untuk swift 4.0
carrotzoe
Terlalu bertele-tele untuk menggambar garis bawah.
khcpietro
38

Inilah yang saya lakukan. Ini bekerja seperti mentega.

1) Tambahkan CoreText.framework ke Frameworks Anda.

2) impor <CoreText / CoreText.h> di kelas di mana Anda membutuhkan label yang digarisbawahi.

3) Tulis kode berikut.

    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];
Sana
sumber
+1 dari saya untuk jawaban ini, karena ini memang bekerja dengan sangat baik, dan ini menunjukkan cara mudah untuk menetapkan rentang karakter tertentu juga (yang saya butuhkan sendiri). Terima kasih! - Erik
Erik van der Neut
19

Gunakan atribut string:

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

Dan kemudian timpa label - (void) drawTextInRect: (CGRect) aRect dan render teks menjadi seperti:

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);

Atau lebih baik lagi daripada menimpa, cukup gunakan OHAttributedLabel yang dibuat oleh Olivier Halligon

Paulo Ferreira
sumber
1
Baris teratas harusNSMutableAttributedString
borrrden
Alasan saya berhenti menggunakan OHAttributedLabel adalah, bahwa - setidaknya bagi saya, tidak mungkin menghitung tinggi teks yang akurat. dalam 10% kasus itu salah. (mungkin karena saya menggunakan font yang berbeda ..)
Guntis Treulands
15

Saya telah menggabungkan beberapa jawaban yang diberikan, untuk membuat subkelas UILabel yang lebih baik (setidaknya untuk kebutuhan saya), yang mendukung:

  • teks multiline dengan berbagai batas label (teks dapat berada di tengah bingkai label, atau berukuran akurat)
  • menggarisbawahi
  • menyerang
  • offset garis bawah / coretan
  • perataan teks
  • ukuran font yang berbeda

https://github.com/GuntisTreulands/UnderLineLabel

Guntis Treulands
sumber
11

Orang-orang, yang tidak ingin membuat subclass view (UILabel / UIButton) dll ... 'forgetButton' dapat diganti dengan label apapun juga.

-(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];
}
karim
sumber
2
-1 untuk memanggil "draw…" sebuah metode yang mengalokasikan UILabel dan menambahkannya ke tampilan.
jcayzac
1
Saya telah mengadaptasi ini menjadi sedikit lebih umum: pastebin.com/QkF9ifpb original tidak memperhitungkan jika label ada dalam subview.
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;
}
Jill Wong
sumber
7

Solusi lain bisa jadi (karena iOS 7) diberi nilai negatif NSBaselineOffsetAttributeName, misalnya Anda NSAttributedStringbisa menjadi:

NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:@"my text goes here'
                                                            attributes:@{NSFontAttributeName: [UIFont fontWithName:@"Helvetica-Regular" size:12],
                                                                         NSForegroundColorAttributeName: [UIColor blackColor],
                                                                         NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle), NSBaselineOffsetAttributeName: @(-3)}];

Semoga ini bisa membantu ;-)

youssman
sumber
7
NSMutableAttributedString *text = [self.myUILabel.attributedText mutableCopy];
[text addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:NSMakeRange(0, text.length)];
self.myUILabel.attributedText = text;
Roman Solodyashkin
sumber
3

Anda dapat membuat label khusus dengan nama UnderlinedLabel dan mengedit fungsi 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
sumber
3

Berikut adalah solusi termudah yang berfungsi untuk saya tanpa menulis kode tambahan.

// 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;
Dhaval Dobariya
sumber
3

Terkadang pengembang kami terjebak dalam bagian desain kecil dari layar UI mana pun. Salah satu persyaratan yang paling menjengkelkan adalah di bawah teks baris. Jangan khawatir, inilah solusinya.

masukkan deskripsi gambar di sini

Menggarisbawahi teks dalam UILabel menggunakan 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];

Menggarisbawahi teks dalam UILabel menggunakan 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
Tuan Javed Multani
sumber
1

Versi kode Kovpas yang disempurnakan (warna dan ukuran garis)

@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
Damien Praca
sumber
1

Saya telah Membuat untuk uilabel multiline dengan garis bawah:

Untuk Font size 8 sampai 13 set int lineHeight = self.font.pointSize + 3;

Untuk ukuran font 14 sampai 20 set 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]; 
}
Piyush
sumber
0

Seperti yang ditunjukkan oleh kovpas, Anda dapat menggunakan kotak pembatas dalam banyak kasus, meskipun tidak selalu dijamin bahwa kotak pembatas akan pas dengan rapi di sekitar teks. Sebuah kotak dengan tinggi 50 dan ukuran font 12 mungkin tidak memberikan hasil yang Anda inginkan tergantung pada konfigurasi UILabel.

Buat kueri UIString dalam UILabel untuk menentukan metrik yang tepat dan gunakan ini untuk menempatkan garis bawah Anda dengan lebih baik terlepas dari kotak pembatas atau bingkai yang melingkupi menggunakan kode gambar yang telah disediakan oleh kovpas.

Anda juga harus melihat properti "leading" UIFont yang memberikan jarak antara baseline berdasarkan font tertentu. Garis dasar adalah tempat Anda ingin garis bawah digambar.

Cari tambahan UIKit ke 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.
gnasher
sumber
Kenny sepertinya saya bisa menggunakan 3 metode untuk mendapatkan lebar baris 1 teks dengan mudah, tapi bagaimana dengan baris ke-2 dan ke-3 dan baris lainnya? Bisakah Anda memberi contoh?
semix
Saya harus mengakui. Sekarang ada cara menggunakan NSString untuk mencapai apa yang Anda inginkan, kecuali orang lain memiliki lebih banyak untuk ditawarkan. Saya harus menyarankan seperti yang lain sebelum saya menggunakan UIWebView dan memasukkan teks Anda ke dalam tampilan: [webView loadHTMLString: @ "<html> <u> Teks yang Digarisbawahi. </u> </html>" baseURL: nil ]; Biarkan ia melakukan tata letak dan penentuan kemana garis harus pergi. Jika ini soal Anda ingin baris ke-n digarisbawahi dan Anda tidak tahu yang mana baris ke-n, itu soal lain.
gnasher
0

Saya menggunakan tampilan garis open source dan baru saja menambahkannya ke subview tombol:

 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];

Ini terinspirasi dari Karim di atas.

David H.
sumber
Anda bisa menggunakan UIVIew. UIView * line = [[UIView alokasi] initWithFrame: frame]; line.backgroundColor = [UIColor lightGrayColor];
dzeikei
0

Berdasarkan Jawaban Kovpas & Damien Praca, berikut adalah implementasi UILabelUnderligned yang juga mendukung textAlignemnt .

#import <UIKit/UIKit.h>

@interface UILabelUnderlined : UILabel

@end

dan implementasinya:

#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
Pascal
sumber
Pembaruan untuk iOS 6 untuk switch: switch (self.textAlignment) {case NSTextAlignmentLeft: case NSTextAlignmentJustified: case NSTextAlignmentNatural: break; case NSTextAlignmentCenter: alignementXOffset = (self.titleLabel.frame.size.width - textSize.width) / 2; istirahat; case NSTextAlignmentRight: alignementXOffset = self.titleLabel.frame.size.width - textSize.width; istirahat; }
pfrank
0

Inilah solusi lain yang lebih sederhana (lebar garis bawah tidak paling akurat tetapi cukup baik untuk saya)

Saya memiliki UIView (_view_underline)yang memiliki latar belakang Putih, tinggi 1 piksel dan saya memperbarui lebarnya setiap kali saya memperbarui teks

// 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];
}
Ege Akpinar
sumber
0

NSUnderlineStyleAttributeName yang mengambil NSNumber (di mana 0 adalah tanpa garis bawah) dapat ditambahkan ke kamus atribut. Saya tidak tahu apakah ini lebih mudah. Tapi, itu lebih mudah untuk tujuan saya.

    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];
epaus
sumber
0

Swift 4.1 ver:

 let underlineAttriString = NSAttributedString(string:"attriString", attributes:
    [NSAttributedStringKey.underlineStyle: NSUnderlineStyle.styleSingle.rawValue])

label.attributedText = underlineAttriString
Abdoelrhman
sumber
0

Anda dapat menggunakan label khusus saya ini! Anda juga dapat menggunakan pembuat antarmuka untuk mengatur

import UIKit


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

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

}
Ucdemir
sumber