web-dev-qa-db-de.com

Text in UIlabel unterstützt

Wie kann ich einen Text unterstreichen, der aus mehreren Stringzeilen bestehen kann? Ich finde, einige Leute schlagen UIWebView vor, aber es ist offensichtlich zu viel Klasse für das reine Text-Rendering.

Meine Gedanken waren, den Startpunkt und die Länge jeder Schnur in jeder Linie herauszufinden ... und eine Linie darunter zu zeichnen.

Ich treffe Probleme bei der Ermittlung der Länge und des Startpunkts der Saite. Kann mir jemand dabei helfen?

Ich habe versucht, -[UILabel textRectForBounds:limitedToNumberOfLines:] zu verwenden. Dies sollte die richtige Zeichnung für den Text sein, oder? Dann muss ich an der Ausrichtung arbeiten. Wie kann ich den Startpunkt jeder Linie erhalten, wenn sie zentriert und richtig ausgerichtet ist?

Ich bin neu hier, also vielen Dank im Voraus.

79
semix

Sie können eine Unterklasse von UILabel erstellen und die drawRect-Methode überschreiben:

- (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:
Ab iOS 6 fügte Apple die Unterstützung von NSAttributedString für UILabel hinzu. Jetzt ist es viel einfacher und funktioniert für mehrere Zeilen:

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

Wenn Sie weiterhin iOS 4 und iOS 5 unterstützen möchten, würde ich empfehlen, TTTAttributedLabel zu verwenden, anstatt das Label manuell zu unterstreichen. Wenn Sie jedoch einzeiliges UILabel unterstreichen müssen und keine Komponenten von Drittanbietern verwenden möchten, wird der obige Code immer noch ausreichen.

134
kovpas

Das habe ich gemacht. Es funktioniert wie Butter.

1) Fügen Sie CoreText.framework zu Ihren Frameworks hinzu.

2) Importieren Sie <CoreText/CoreText.h> in die Klasse, in der Sie ein unterstrichenes Label benötigen.

3) Schreiben Sie den folgenden Code.

    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

In Swift:

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

Verwenden Sie eine Attributzeichenfolge:

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

Und überschreiben Sie dann das Label - (void) drawTextInRect: (CGRect) aRect und rendern Sie den Text in etwa wie folgt:

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

Oder besser noch, anstatt zu überschreiben, verwenden Sie einfach das von Olivier Halligon erstellte OHAttributedLabel

19
Paulo Ferreira

Ich habe einige der bereitgestellten Antworten kombiniert, um (zumindest für meine Anforderungen) eine bessere UILabel-Unterklasse zu erstellen, die Folgendes unterstützt:

  • mehrzeiliger Text mit verschiedenen Beschriftungsgrenzen (Text kann sich in der Mitte des Beschriftungsrahmens befinden oder genaue Größe haben)
  • unterstreichen
  • strikeout
  • linienversatz unterstrichen/streichen
  • textausrichtung
  • verschiedene Schriftgrößen

https://github.com/GuntisTreulands/UnderLineLabel

16

Personen, die die Ansicht nicht untergliedern möchten (UILabel/UIButton) usw. ....__ 'forgetButton' kann auch durch ein beliebiges Label ersetzt werden.

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

Eine andere Lösung könnte (seit iOS 7) ein negativer Wert für NSBaselineOffsetAttributeName sein. Beispielsweise könnte Ihre NSAttributedString sein: 

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

Hoffe, das wird helfen ;-)

7
youssman

Hier ist die einfachste Lösung, die für mich funktioniert, ohne zusätzliche Codes zu schreiben.

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

Sie können ein benutzerdefiniertes Label mit dem Namen UnderlinedLabel erstellen und die drawRect-Funktion bearbeiten.

#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

Eine verbesserte Version des Codes von Kovpas (Farbe und Liniengröße)

@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

Ich habe für Multilinien mit Unterstrichen erstellt:

Für Schriftgröße 8 bis 13 setzen Sie int lineHeight = self.font.pointSize + 3;

Für Schriftgröße 14 bis 20 setzen Sie 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, das eine NSNumber (wobei 0 keine Unterstreichung ist) enthält, kann zu einem Attributwörterbuch hinzugefügt werden. Aber es war leichter für meine Zwecke.

    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

Hier ist eine andere, einfachere Lösung (Breite der Unterstreichung ist nicht genau, aber für mich gut genug)

Ich habe ein UIView (_view_underline) mit weißem Hintergrund und einer Höhe von 1 Pixel. Ich aktualisiere die Breite jedes Mal, wenn ich den Text aktualisiere

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

Basierend auf den Antworten von Kovpas & Damien Praca, ist hier eine Implementierung von UILabelUnderligned, die auch textAlignemnt unterstützt.

#import <UIKit/UIKit.h>

@interface UILabelUnderlined : UILabel

@end

und die Umsetzung:

#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

Wie kovpas gezeigt hat, können Sie den Begrenzungsrahmen in den meisten Fällen verwenden, obwohl nicht immer garantiert werden kann, dass der Begrenzungsrahmen sauber in den Text passt. Eine Box mit einer Höhe von 50 und einer Schriftgröße von 12 kann je nach der UILabel-Konfiguration möglicherweise nicht die gewünschten Ergebnisse liefern. 

Fragen Sie den UIString innerhalb des UILabels ab, um die genauen Metriken zu ermitteln, und verwenden Sie diese, um die Unterstreichung unabhängig vom umgebenden Begrenzungsrahmen oder Rahmen mit dem von kovpas bereits bereitgestellten Zeichnungscode besser zu positionieren.

Sie sollten sich auch die "führende" Eigenschaft von UIFont ansehen, die den Abstand zwischen Baselines basierend auf einer bestimmten Schriftart angibt. An der Grundlinie sollte der Unterstrich gezeichnet werden.

Schauen Sie sich die UIKit-Ergänzungen zu NSString an:

(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

Ich verwende eine Open-Source-Zeilenansicht und fügte sie einfach den Button-Subviews hinzu:

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

Dies wurde von Karim oben inspiriert.

0
David H