UIlabel'de metnin altını çiz


89

Birden çok satırlık dize olabilen bir metnin altını nasıl çizebilirim? Bazı insanların UIWebView'ı önerdiğini görüyorum, ancak bu sadece metin oluşturma için çok ağır bir sınıf.

Düşüncelerim, her satırdaki her dizenin başlangıç ​​noktasını ve uzunluğunu bulmaktı. Ve buna göre bir çizgi çizin.

İpin uzunluğunu ve başlangıç ​​noktasını nasıl bulacağım konusunda sorunlarla karşılaşıyorum.

Kullanmaya çalıştım -[UILabel textRectForBounds:limitedToNumberOfLines:], bu metin için sınır çizgisi olmalı değil mi? O halde uyum üzerinde çalışmam mı gerekiyor? Ortaya hizalandığında ve doğru hizalandığında her satırın başlangıç ​​noktasını nasıl alabilirim?


Yanıtlar:


137

UILabel'den alt sınıflandırma yapabilir ve drawRect yöntemini geçersiz kılabilirsiniz:

- (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'dan itibaren Apple, UILabel için NSAttributedString desteğini ekledi, bu nedenle artık çok daha kolay ve birden çok satır için çalışıyor:

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

Hala iOS 4 ve iOS 5'i desteklemek istiyorsanız, manuel olarak etiketin altını çizmek yerine TTTAttributedLabel'i kullanmanızı öneririm . Bununla birlikte, tek satırlık UILabel'in altını çizmeniz gerekiyorsa ve üçüncü taraf bileşenlerini kullanmak istemiyorsanız, yukarıdaki kod yine de işe yarayacaktır.


3
Sanırım bu, dizenin son satırı için sadece bir alt çizgi çizecek, değil mi? Diğer satırlardaki dizenin altı çizili ne olacak?
semix

2
birden fazla satır yapmıyor, ancak bulabildiğim en iyisi bu, bu yüzden sanırım birden çok satır söz konusu değil. Sanırım düşünebileceğim bir sonraki en iyi çözüm, yazı tipinde altı çizili bir yazı tipini içe aktarmak. Bu yalnızca yazı tiplerini içe aktarabileceğiniz ios 4.0+ sürümünde çalışır.
DonnaLea

merhaba, bunun ios ui standartlarından herhangi birini ihlal edip etmediğini bilmek istiyorum.
thndrkiss

Apple'ın uygulaması (ikinci öneri) satırın altına düşen karakterleri desteklemiyor mu? screencast.com/t/NGvQJqoWAD3J
pfrank

UILabel için NSAttributedString desteğini kullanırsak, g, p & q gibi alfabeler için alt çizgi kesiliyor. Sorunla karşı karşıya olan var mı? Örnek: Giriş
dev4u

46

Swift'de:

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

Swift 3'te yapmanız gereken tek şey .StyleSingle'ı .styleSingle'a değiştirmek, bu Swift3'te camelCased ama harika bir cevap!
Josh O'Connor

.RawValue olmadan, bu benim için bir çökmeye neden oluyordu.
jackofallcode

swift 4.0 için yalnızca .rawValue'ye ihtiyacınız olacak
carrotzoe

Sadece altını çizmek için çok ayrıntılı.
khcpietro

38

Yaptığım bu. Tereyağı gibi çalışır.

1) Çerçevelerinize CoreText.framework ekleyin.

2) altı çizili etikete ihtiyaç duyduğunuz sınıfa <CoreText / CoreText.h> aktarın.

3) Aşağıdaki kodu yazın.

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

Bu cevap için benden +1, çünkü bu gerçekten harika çalışıyor ve belirli bir karakter aralığı belirlemenin kolay bir yolunu da gösteriyor (benim ihtiyacım olan şey buydu). Teşekkürler! - Erik
Erik van der Neut

19

Bir öznitelik dizesi kullanın:

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

Ve sonra - (void) drawTextInRect: (CGRect) aRect etiketini geçersiz kılın ve metni aşağıdaki gibi oluşturun:

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

Ya da daha iyisi geçersiz kılmak yerine Olivier Halligon tarafından oluşturulan OHAttributedLabel'i kullanın.


1
Üst satırda olmalıdırNSMutableAttributedString
borrrden

OHAttributedLabel'i kullanmayı bırakmamın nedeni şuydu - en azından benim için doğru metin yüksekliğini hesaplamak mümkün değildi. % 10 vakada yanlıştı. (belki farklı yazı tipi kullandığım için ..)
Guntis Treulands

15

Daha iyi (en azından gereksinimlerim için) oluşturmak için verilen cevaplardan bazılarını birleştirdim, UILabel alt sınıfı şunları destekler:

  • çeşitli etiket sınırlarına sahip çok satırlı metin (metin, etiket çerçevesinin ortasında veya doğru boyutta olabilir)
  • altını çizmek
  • üstü çizili
  • altı çizili / üstü çizili çizgi uzaklığı
  • Metin hizalama
  • farklı yazı tipi boyutları

https://github.com/GuntisTreulands/UnderLineLabel


11

Görünümü alt sınıflara ayırmak istemeyen kişiler (UILabel / UIButton) vb. 'ForgotButton' da herhangi bir etiket ile değiştirilebilir.

-(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, bir UILabel ayıran ve görünüme ekleyen bir yöntemi "çiz ..." çağırmak için.
jcayzac

1
Bunu biraz daha genel olacak şekilde uyarladım: pastebin.com/QkF9ifpb original, etiketin bir alt görünümde olup olmadığını hesaba katmıyor.
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

Başka bir çözüm de (iOS 7'den beri) 'a negatif bir değer verilebilir NSBaselineOffsetAttributeName, örneğin sizin NSAttributedStringşunlar olabilir:

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

Umarım bu yardımcı olur ;-)


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

3

UnderlinedLabel adıyla özel bir etiket oluşturabilir ve drawRect işlevini düzenleyebilirsiniz.

#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

İşte ek kodlar yazmadan benim için çalışan en kolay çözüm.

// 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

Bazen geliştirici, herhangi bir kullanıcı arayüzü ekranının küçük tasarım bölümünde sıkışıp kalıyoruz. En rahatsız edici gerekliliklerden biri, satır altı metindir. Endişelenmeyin, çözüm burada.

görüntü açıklamasını buraya girin

Hedef C'yi kullanarak UILabel'deki bir metnin altını çizme

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

Swift kullanarak UILabel'de bir metnin altını çizme

 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 kodunun geliştirilmiş bir versiyonu (renk ve çizgi boyutu)

@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

Alt çizgi ile çok satırlı uilabel için oluşturdum:

Yazı tipi boyutu 8 ila 13 için int lineHeight = self.font.pointSize + 3;

14-20 yazı tipi boyutu için 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'ın gösterdiği gibi, sınırlayıcı kutuyu çoğu durumda kullanabilirsiniz, ancak sınırlayıcı kutunun metnin etrafına düzgün bir şekilde sığacağı her zaman garanti edilmez. Yüksekliği 50 ve yazı tipi boyutu 12 olan bir kutu, UILabel yapılandırmasına bağlı olarak istediğiniz sonuçları vermeyebilir.

Tam ölçümlerini belirlemek için UILabel içindeki UIString'i sorgulayın ve bunları, kovpas tarafından sağlanan çizim kodunu kullanarak çevreleyen sınırlayıcı kutu veya çerçeveden bağımsız olarak alt çizginizi daha iyi yerleştirmek için kullanın.

Ayrıca, belirli bir yazı tipine göre taban çizgileri arasındaki mesafeyi veren UIFont'un "öncü" özelliğine de bakmalısınız. Taban çizgisi, alt çizginizin çizilmesini istediğiniz yerdir.

NSString'e UIKit eklerini arayın:

(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, 1. satırın genişliğini kolayca elde etmek için 3 yöntemi kullanabilirim gibi görünüyor, peki ya 2. 3. ve diğer satırlar? Bir örnek verebilir misin?
semix

Kabul etmeliyim. Başka birinin sunabileceği daha fazla şey yoksa, istediğiniz şeyi elde etmek için NSString'i kullanmanın bir yolu var. UIWebView'ı kullanmam ve metninizi görünüme yerleştirmem için benden önceki diğerleri gibi önermem gerekecek: [webView loadHTMLString: @ "<html> <u> Altı Çizili Metin </u> </html>" baseURL: nil ]; Çizgilerin nereye gitmesi gerektiğinin düzenini ve belirlenmesini yapsın. Eğer n'inci çizginin altının çizilmesini istiyorsanız ve hangisinin n'inci satır olduğunu bilemiyorsanız, bu başka bir konudur.
gnasher

0

Açık kaynak satır görünümü kullanıyorum ve bunu düğme alt görünümlerine ekledim:

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

Bu, yukarıdaki Karim'den esinlenmiştir.


Sadece UIVIew'i kullanabilirsiniz. UIView * satır = [[UIView tahsisi] initWithFrame: çerçeve]; line.backgroundColor = [UIColor lightGrayColor];
dzeikei

0

Kovpas & Damien Praca's Answers'a dayanarak, burada textAlignemnt'i de destekleyen UILabelUnderligned uygulamasının bir uygulaması var .

#import <UIKit/UIKit.h>

@interface UILabelUnderlined : UILabel

@end

ve uygulama:

#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

Anahtar için iOS 6 güncellemesi: switch (self.textAlignment) {case NSTextAlignmentLeft: case NSTextAlignmentJustified: case NSTextAlignmentNatural: break; case NSTextAlignmentCenter: alignementXOffset = (self.titleLabel.frame.size.width - textSize.width) / 2; kırmak; case NSTextAlignmentRight: alignementXOffset = self.titleLabel.frame.size.width - textSize.width; kırmak; }
pfrank

0

İşte başka, daha basit bir çözüm (alt çizginin genişliği en doğru değil ama benim için yeterince iyiydi)

(_view_underline)Beyaz arka plana sahip bir UIView var, yüksekliği 1 piksel ve metni her güncellediğimde genişliğini güncelliyorum

// 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

Bir NSNumber alan NSUnderlineStyleAttributeName (burada 0, altı çizili değildir) bir öznitelik sözlüğüne eklenebilir. Bunun daha kolay olup olmadığını bilmiyorum. Ama benim amaçlarım için daha kolaydı.

    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 sürümü:

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

label.attributedText = underlineAttriString

0

Bunu benim özel etiketimi kullanabilirsiniz! Ayrıca arayüz oluşturucuyu kullanarak

import UIKit


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

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

}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.