web-dev-qa-db-fra.com

Texte souligné dans UIlabel

Comment souligner un texte qui pourrait comporter plusieurs lignes de chaîne? .__ Je trouve que certaines personnes suggèrent UIWebView, mais il s'agit évidemment d'une classe trop lourde pour un rendu de texte uniquement.

Mon idée était de déterminer le point de départ et la longueur de chaque chaîne de chaque ligne ..__ Et de dessiner une ligne en conséquence.

Je rencontre des problèmes pour déterminer la longueur et le point de départ de la chaîne. Quelqu'un peut-il m'aider à ce sujet?

J'ai essayé d'utiliser -[UILabel textRectForBounds:limitedToNumberOfLines:], cela devrait être le rectangle de délimitation du dessin pour le texte non? Ensuite, je dois travailler sur l’alignement? Comment puis-je obtenir le point de départ de chaque ligne quand elle est justifiée au centre et justifiée à droite?

Je suis nouveau ici, alors merci d'avance.

79
semix

Vous pouvez sous-classer à partir de UILabel et substituer la méthode 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:
À partir de iOS 6, Apple a ajouté la prise en charge de Uilabel par NSAttributedString, elle est donc beaucoup plus simple et fonctionne pour plusieurs lignes

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

Si vous souhaitez toujours prendre en charge iOS 4 et iOS 5, nous vous recommandons d'utiliser TTTAttributedLabel plutôt que de souligner manuellement le libellé. Toutefois, si vous avez besoin de souligner UILabel sur une ligne et de ne pas utiliser de composants tiers, le code ci-dessus fera toujours l'affaire.

134
kovpas

C'est ce que j'ai fait. Cela fonctionne comme du beurre.

1) Ajoutez CoreText.framework à vos cadres.

2) importez <CoreText/CoreText.h> dans la classe où vous avez besoin d’un libellé souligné.

3) Écris le code suivant.

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

En rapide:

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

Utilisez une chaîne d'attribut:

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

Et puis écrasez le libellé - (void) drawTextInRect: (CGRect) aRect et restituez le texte de la manière suivante:

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

Ou mieux encore, au lieu de remplacer, utilisez simplement le OHAttributedLabel créé par Olivier Halligon

19
Paulo Ferreira

J'ai combiné certaines des réponses fournies pour créer une meilleure sous-classe UILabel (du moins pour mes besoins), qui prend en charge:

  • texte multiligne avec diverses limites d'étiquette (le texte peut être au milieu du cadre de l'étiquette ou être de taille précise)
  • souligner
  • strikeout
  • ligne de soulignement/décalage en ligne
  • alignement du texte
  • différentes tailles de police

https://github.com/GuntisTreulands/UnderLineLabel

16
Guntis Treulands

Les personnes qui ne souhaitent pas sous-classer la vue (UILabel/UIButton), etc., etc., peuvent également être remplacées par une étiquette.

-(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];
}
11
karim
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;
}
8
Jill Wong
NSMutableAttributedString *text = [self.myUILabel.attributedText mutableCopy];
[text addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:NSMakeRange(0, text.length)];
self.myUILabel.attributedText = text;
7
Roman Solodyashkin

Une autre solution pourrait être (depuis iOS 7) de donner une valeur négative à NSBaselineOffsetAttributeName, par exemple votre NSAttributedString pourrait être: 

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

J'espère que ça va aider ;-)

7
youssman

Voici la solution la plus simple qui fonctionne pour moi sans écrire de codes supplémentaires.

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

Vous pouvez créer une étiquette personnalisée avec le nom UnderlinedLabel et modifier la fonction 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
nfinfu

Une version améliorée du code de Kovpas (couleur et taille de trait)

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

J'ai créé pour uilabel multiligne avec soulignement:

Pour une taille de police de 8 à 13, définissez int lineHeight = self.font.pointSize + 3;

Pour une taille de police de 14 à 20, définissez 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]; 
}
1
Piyush

NSUnderlineStyleAttributeName qui prend un NSNumber (où 0 n'est pas souligné) peut être ajouté à un dictionnaire d'attributs .. Je ne sais pas si c'est plus facile Mais c'était plus facile pour mes objectifs.

    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
epaus

Voici une autre solution plus simple (la largeur du soulignement n’est pas très précise mais c’est suffisant pour moi)

J'ai un (_view_underline) UIView qui a un fond blanc, une hauteur de 1 pixel et je modifie sa largeur à chaque fois que je mets à jour le texte

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

Basé sur les réponses de Kovpas & Damien Praca, voici une implémentation de UILabelUnderligned qui prend également en charge textAlignemnt .

#import <UIKit/UIKit.h>

@interface UILabelUnderlined : UILabel

@end

et la mise en œuvre:

#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
0
Pascal

Swift 4.1 ver: 

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

label.attributedText = underlineAttriString
0
Abdoelrhman

Comme kovpas l'a montré, vous pouvez utiliser le cadre de sélection dans la plupart des cas, bien qu'il ne soit pas toujours garanti que le cadre de sélection s'intègrera parfaitement au texte. Une boîte d'une hauteur de 50 et d'une taille de police de 12 peut ne pas donner les résultats souhaités selon la configuration UILabel. 

Interrogez UIString dans UILabel pour déterminer ses métriques exactes et utilisez-les pour mieux placer votre soulignement, quel que soit le cadre de sélection ou le cadre englobant, à l'aide du code de dessin déjà fourni par kovpas.

Vous devriez également regarder la propriété "principale" d'UIFont qui donne la distance entre les lignes de base en fonction d'une police particulière. La ligne de base est l'endroit où vous souhaitez que votre soulignement soit tracé.

Recherchez les ajouts d'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.
0
gnasher

J'utilise une vue en ligne open source que je viens d'ajouter aux sous-vues des boutons:

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

Ceci a été inspiré par Karim ci-dessus.

0
David H