Sottolinea il testo in UIlabel


89

Come posso sottolineare un testo che potrebbe essere costituito da più righe di stringa? Trovo che alcune persone suggeriscano UIWebView, ma è ovviamente una classe troppo pesante per il solo rendering del testo.

Il mio pensiero era quello di capire il punto iniziale e la lunghezza di ogni stringa in ogni riga. E traccia una linea sotto di essa di conseguenza.

Ho problemi a capire la lunghezza e il punto di inizio della stringa.

Ho provato a usare -[UILabel textRectForBounds:limitedToNumberOfLines:], questo dovrebbe essere il rettangolo di delimitazione del disegno per il testo, giusto? Allora devo lavorare sull'allineamento? Come posso ottenere il punto iniziale di ogni linea quando è giustificata al centro e a destra?


1

Risposte:


137

Puoi sottoclasse da UILabel e sovrascrivere il metodo 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:
A partire da iOS 6 Apple ha aggiunto il supporto NSAttributedString per UILabel, quindi ora è molto più semplice e funziona per più linee:

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

Se desideri ancora supportare iOS 4 e iOS 5, ti consiglio di utilizzare TTTAttributedLabel anziché sottolineare l'etichetta manualmente. Tuttavia, se è necessario sottolineare UILabel su una riga e non si desidera utilizzare componenti di terze parti, il codice sopra potrebbe comunque fare il trucco.


3
Immagino che questo disegnerà solo una sottolineatura per l'ultima riga di stringa, giusto? E la sottolineatura per la stringa in altre righe?
semix

2
non fa più righe, ma questo è il meglio che posso trovare, quindi immagino che più righe siano fuori questione. Immagino che la prossima migliore soluzione a cui riesco a pensare sia importare un carattere che ha una sottolineatura incorporata nel carattere. Funzionerebbe solo da iOS 4.0+ dove puoi importare i caratteri.
DonnaLea

ciao, voglio sapere se questo viola uno qualsiasi degli standard ios ui.
thndrkiss

L'implementazione di Apple (il secondo suggerimento) non supporta i caratteri che vanno sotto la linea? screencast.com/t/NGvQJqoWAD3J
pfrank

Se usiamo il supporto NSAttributedString per UILabel, per alfabeti come g, la sottolineatura p & q sta troncando. Qualcuno sta affrontando il problema? Esempio: accesso
dev4u

46

In Swift:

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

L'unica cosa che devi fare in Swift 3 è cambiare .StyleSingle in .styleSingle, è camelCased in Swift3, ma ottima risposta!
Josh O'Connor

Senza .rawValue, questo stava causando un arresto anomalo per me.
jackofallcode

avresti bisogno solo di .rawValue per swift 4.0
carrotzoe

Troppo prolisso per disegnare solo la sottolineatura.
khcpietro

38

Questo è quello che ho fatto. Funziona come il burro.

1) Aggiungi CoreText.framework ai tuoi Frameworks.

2) importa <CoreText / CoreText.h> nella classe in cui hai bisogno dell'etichetta sottolineata.

3) Scrivi il seguente codice.

    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 da me per questa risposta, perché funziona davvero brillantemente e dimostra un modo semplice per impostare anche un intervallo di caratteri specifico (che è quello di cui avevo bisogno io stesso). Grazie! - Erik
Erik van der Neut

19

Utilizza una stringa di attributo:

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

E quindi sovrascrivi l'etichetta - (void) drawTextInRect: (CGRect) aRect e rendi il testo in qualcosa di simile:

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

O meglio ancora invece di sovrascrivere basta usare OHAttributedLabel creato da Olivier Halligon


1
La linea superiore dovrebbe essereNSMutableAttributedString
borrrden

Il motivo per cui ho abbandonato l'uso di OHAttributedLabel era che, almeno per me, non era possibile calcolare l'altezza del testo precisa. nel 10% dei casi non era corretto. (forse perché stavo usando un font diverso ..)
Guntis Treulands

15

Ho combinato alcune delle risposte fornite, per creare una sottoclasse UILabel migliore (almeno per le mie esigenze), che supporta:

  • testo multilinea con vari limiti di etichetta (il testo può trovarsi al centro della cornice dell'etichetta o di dimensioni precise)
  • sottolineare
  • strikeout
  • linea di sottolineatura / barrata offset
  • allineamento del testo
  • diverse dimensioni dei caratteri

https://github.com/GuntisTreulands/UnderLineLabel


11

Le persone che non vogliono sottoclassare la vista (UILabel / UIButton) ecc ... "dimenticareButton" possono essere sostituite anche da qualsiasi etichetta.

-(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 per chiamare "draw ..." un metodo che alloca una UILabel e la aggiunge alla vista.
jcayzac

1
L'ho adattato per essere un po 'più generico: pastebin.com/QkF9ifpb original non tiene conto se l'etichetta è in una sottoview.
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

Un'altra soluzione potrebbe essere (da iOS 7) dato un valore negativo a NSBaselineOffsetAttributeName, ad esempio il tuo NSAttributedStringpotrebbe essere:

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

Spero che questo ti aiuti ;-)


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

3

È possibile creare un'etichetta personalizzata con il nome UnderlinedLabel e modificare la funzione 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

Ecco la soluzione più semplice che funziona per me senza scrivere codici aggiuntivi.

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

A volte noi sviluppatori siamo bloccati in piccole parti di progettazione di qualsiasi schermata dell'interfaccia utente. Uno dei requisiti più irritanti è il testo sotto la riga. Non preoccuparti, ecco la soluzione.

inserisci qui la descrizione dell'immagine

Sottolineare un testo in un'etichetta UIL utilizzando 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];

Sottolineare un testo in UILabel utilizzando 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

Una versione migliorata del codice di Kovpas (colore e dimensione della linea)

@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

Ho creato un'etichetta su più righe con sottolineatura:

Per la dimensione del carattere da 8 a 13 impostare int lineHeight = self.font.pointSize + 3;

Per la dimensione del carattere da 14 a 20 impostare 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

Come ha dimostrato kovpas, nella maggior parte dei casi puoi usare il riquadro di delimitazione, sebbene non sia sempre garantito che il riquadro di delimitazione si adatti perfettamente al testo. Una casella con un'altezza di 50 e una dimensione del carattere di 12 potrebbe non dare i risultati desiderati a seconda della configurazione di UILabel.

Interroga la stringa UIS all'interno di UILabel per determinare le sue metriche esatte e usale per posizionare meglio la tua sottolineatura indipendentemente dal riquadro di delimitazione o dalla cornice che lo racchiude utilizzando il codice di disegno già fornito da kovpas.

Dovresti anche esaminare la proprietà "leading" di UIFont che fornisce la distanza tra le linee di base in base a un particolare carattere. La linea di base è dove vorresti che fosse disegnata la tua sottolineatura.

Cerca le aggiunte UIKit a 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 sembra che io possa usare i 3 metodi per ottenere facilmente la larghezza della prima riga di testo, ma che ne dici della seconda terza e delle altre righe? Puoi fare un esempio?
semix

Devo ammettere. Ora è possibile utilizzare NSString per ottenere ciò che si desidera, a meno che qualcun altro non abbia altro da offrire. Dovrò suggerire come gli altri prima di me di usare UIWebView e inserire il tuo testo nella vista: [webView loadHTMLString: @ "<html> <u> Underlined Text. </u> </html>" baseURL: nil ]; Lascia che faccia il layout e la determinazione di dove dovrebbero andare le linee. Se è una questione che vuoi sottolineare l'ennesima riga e non puoi sapere qual è l'ennesima riga, è un'altra cosa.
gnasher

0

Uso una visualizzazione in linea open source e l'ho appena aggiunta alle sottoview dei pulsanti:

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

Questo è stato ispirato da Karim sopra.


Potresti semplicemente usare UIVIew. UIView * riga = [[UIView alloc] initWithFrame: frame]; line.backgroundColor = [UIColor lightGrayColor];
dzeikei

0

Basata sulle risposte di Kovpas e Damien Praca, ecco un'implementazione di UILabelUnderligned che supporta anche textAlignemnt .

#import <UIKit/UIKit.h>

@interface UILabelUnderlined : UILabel

@end

e l'implementazione:

#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

Aggiornamento per iOS 6 per switch: switch (self.textAlignment) {case NSTextAlignmentLeft: case NSTextAlignmentJustified: case NSTextAlignmentNatural: break; case NSTextAlignmentCenter: alignementXOffset = (self.titleLabel.frame.size.width - textSize.width) / 2; rompere; case NSTextAlignmentRight: alignementXOffset = self.titleLabel.frame.size.width - textSize.width; rompere; }
pfrank

0

Ecco un'altra soluzione più semplice (la larghezza della sottolineatura non è la più precisa ma per me era abbastanza buona)

Ho una UIView (_view_underline)con sfondo bianco, altezza di 1 pixel e aggiorno la sua larghezza ogni volta che aggiorno il testo

// 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 che accetta un NSNumber (dove 0 non è una sottolineatura) può essere aggiunto a un dizionario degli attributi. Non so se sia più facile. Ma era più facile per i miei scopi.

    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 ver:

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

label.attributedText = underlineAttriString

0

Puoi usare questa mia etichetta personalizzata! Puoi anche usare il generatore di interfacce per impostare

import UIKit


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

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

}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.