web-dev-qa-db-ja.com

UIlabelのテキストに下線を引く

複数行の文字列である可能性があるテキストに下線を付けるにはどうすればよいですか? UIWebViewを提案する人もいますが、明らかにテキストレンダリングには重すぎるクラスです。

私の考えは、各行の各文字列の開始点と長さを把握することでした。そして、それに応じて線を引きます。

私は、文字列の長さと開始点を把握する方法で問題に出会います。

-[UILabel textRectForBounds:limitedToNumberOfLines:]を使用しようとしましたが、これはテキストの描画境界四角形である必要がありますか?その後、私はアライメントに取り組む必要がありますか?中央揃えおよび右揃えの場合、どのようにして各行の開始点を取得できますか?

81
semix

UILabelからサブクラス化し、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:
iOS 6 Appleの時点で、UILabelのNSAttributedStringサポートが追加されたため、はるかに簡単になり、複数行で機能します。

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

それでもiOS 4およびiOS 5をサポートしたい場合は、ラベルに手動で下線を付けるのではなく、 TTTAttributedLabel を使用することをお勧めします。ただし、1行のUILabelに下線を引く必要があり、サードパーティのコンポーネントを使用したくない場合は、上記のコードで問題を解決できます。

134
kovpas

これは私がやったことです。バターのように機能します。

1)CoreText.frameworkをフレームワークに追加します。

2)下線付きラベルが必要なクラスに<CoreText/CoreText.h>をインポートします。

3)次のコードを記述します。

    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

Swiftの場合:

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

以下をサポートするUILabelサブクラスを作成するために、提供された回答のいくつかを結合しました(少なくとも私の要件では)。

  • さまざまなラベル境界のある複数行テキスト(テキストはラベルフレームの中央、または正確なサイズにすることができます)
  • 下線
  • strikeout
  • 下線/取り消し線のオフセット
  • テキストの配置
  • 異なるフォントサイズ

https://github.com/GuntisTreulands/UnderLineLabel

15

ビュー(UILabel/UIButton)などをサブクラス化することを望まない人...「forgetButton」は、任意のラベルに置き換えることもできます。

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

別の解決策は(iOS 7以降)NSBaselineOffsetAttributeNameに負の値を指定することです。たとえば、NSAttributedStringは次のようになります。

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

これが役立つことを願っています;-)

7
youssman

追加のコードを書かずに私のために働く最も簡単な解決策は次のとおりです。

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

UnderlinedLabelという名前のカスタムラベルを作成し、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

Kovpasのコードの拡張バージョン(色と行サイズ)

@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

私は下線付きの複数行のUIラベルを作成しました:

フォントサイズ8〜13の場合、int lineHeight = self.font.pointSize + 3;を設定します。

フォントサイズが14〜20の場合、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

NSNumber(0は下線なし)をとるNSUnderlineStyleAttributeNameを属性辞書に追加できます。これが簡単かどうかはわかりません。しかし、私の目的にとっては簡単でした。

    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

ここに、別のより簡単な解決策があります(下線の幅は最も正確ではありませんが、私にとっては十分でした)

UIView (_view_underline)があり、その背景は白で、高さは1ピクセルで、テキストを更新するたびに幅を更新します

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

Kovpas&Damien Pracaの回答に基づいて、ここにtextAlignemntもサポートするUILabelUnderlignedの実装があります。

#import <UIKit/UIKit.h>

@interface UILabelUnderlined : UILabel

@end

および実装:

#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

Kovpasが示したように、ほとんどの場合、境界ボックスを使用できますが、境界ボックスがテキストの周りにきちんと収まることは常に保証されません。 UILabelの構成によっては、高さが50でフォントサイズが12のボックスでは、希望する結果が得られない場合があります。

UILabel内のUIStringを照会して正確なメトリックを決定し、これらを使用して、kovpasによって既に提供されている描画コードを使用して、境界ボックスまたはフレームに関係なく下線を配置します。

また、特定のフォントに基づいてベースライン間の距離を与えるUIFontの「主要な」プロパティを確認する必要があります。ベースラインは、下線を引く場所です。

NSStringに追加されたUIKitを検索します。

(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

私はオープンソースのラインビューを使用し、ボタンサブビューに追加しました:

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

これは上記のカリムに触発されました。

0
David H