単一のUILabel内の太字と太字以外のテキスト?


254

太字テキストと太字以外のテキストの両方をuiLabelに含めるにはどうすればよいでしょうか。

私はUIWebViewを使用したくありません。NSAttributedStringを使用してこれが可能である可能性があることも読んだことがありますが、それを使用する方法がわかりません。何か案は?

Appleはいくつかのアプリでこれを実現しています。スクリーンショットの例:リンクテキスト

ありがとう!-ドム


以前のスタックオーバーフローからこのトピックを確認してください。(基本的に、2つのUILabelを作成し、それらを互いに相対的に正しく配置します。)
samkass 2010

回答:


360

更新

Swiftでは、構文が短いだけでなく、iOS5の古いものを処理する必要がないため、すべてが本当にシンプルになります。

スウィフト5

func attributedString(from string: String, nonBoldRange: NSRange?) -> NSAttributedString {
    let fontSize = UIFont.systemFontSize
    let attrs = [
        NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: fontSize),
        NSAttributedString.Key.foregroundColor: UIColor.black
    ]
    let nonBoldAttribute = [
        NSAttributedString.Key.font: UIFont.systemFont(ofSize: fontSize),
    ]
    let attrStr = NSMutableAttributedString(string: string, attributes: attrs)
    if let range = nonBoldRange {
        attrStr.setAttributes(nonBoldAttribute, range: range)
    }
    return attrStr
}

スウィフト3

func attributedString(from string: String, nonBoldRange: NSRange?) -> NSAttributedString {
    let fontSize = UIFont.systemFontSize
    let attrs = [
        NSFontAttributeName: UIFont.boldSystemFont(ofSize: fontSize),
        NSForegroundColorAttributeName: UIColor.black
    ]
    let nonBoldAttribute = [
        NSFontAttributeName: UIFont.systemFont(ofSize: fontSize),
    ]
    let attrStr = NSMutableAttributedString(string: string, attributes: attrs)
    if let range = nonBoldRange {
        attrStr.setAttributes(nonBoldAttribute, range: range)
    }
    return attrStr
}

使用法:

let targetString = "Updated 2012/10/14 21:59 PM"
let range = NSMakeRange(7, 12)

let label = UILabel(frame: CGRect(x:0, y:0, width:350, height:44))
label.backgroundColor = UIColor.white
label.attributedText = attributedString(from: targetString, nonBoldRange: range)
label.sizeToFit()

ボーナス:国際化

一部の人々は国際化についてコメントしました。私は個人的にはこれはこの質問の範囲外であると思いますが、説明の目的でこれを行う方法です

// Date we want to show
let date = Date()

// Create the string.
// I don't set the locale because the default locale of the formatter is `NSLocale.current` so it's good for internationalisation :p
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .short
let targetString = String(format: NSLocalizedString("Update %@", comment: "Updated string format"),
                          formatter.string(from: date))

// Find the range of the non-bold part
formatter.timeStyle = .none
let nonBoldRange = targetString.range(of: formatter.string(from: date))

// Convert Range<Int> into NSRange
let nonBoldNSRange: NSRange? = nonBoldRange == nil ?
    nil :
    NSMakeRange(targetString.distance(from: targetString.startIndex, to: nonBoldRange!.lowerBound),
                targetString.distance(from: nonBoldRange!.lowerBound, to: nonBoldRange!.upperBound))

// Now just build the attributed string as before :)
label.attributedText = attributedString(from: targetString,
                                        nonBoldRange: nonBoldNSRange)

結果(英語と日本語のLocalizable.stringsが使用可能であると想定)

ここに画像の説明を入力してください

ここに画像の説明を入力してください


iOS6以降の以前の回答(Objective-Cは引き続き機能します):

iOS6ではUILabelUIButtonUITextViewUITextField、サポートは、私たちが作成する必要はありません手段文字列起因するCATextLayer起因する文字列のための私達の受信者として複数可。さらに、属性付き文字列を作成するために、CoreTextで遊ぶ必要はもうありません:) obj-c Foundation.frameworkのような新しいクラスNSParagraphStyleと、私たちの生活を容易にする他の定数があります。わーい!

したがって、次の文字列がある場合:

NSString *text = @"Updated: 2012/10/14 21:59"

属性付き文字列を作成するだけです。

if ([_label respondsToSelector:@selector(setAttributedText:)])
{
    // iOS6 and above : Use NSAttributedStrings

    // Create the attributes
    const CGFloat fontSize = 13;
    NSDictionary *attrs = @{
        NSFontAttributeName:[UIFont boldSystemFontOfSize:fontSize],
        NSForegroundColorAttributeName:[UIColor whiteColor]
    };
    NSDictionary *subAttrs = @{
        NSFontAttributeName:[UIFont systemFontOfSize:fontSize]
    };

    // Range of " 2012/10/14 " is (8,12). Ideally it shouldn't be hardcoded
    // This example is about attributed strings in one label
    // not about internationalisation, so we keep it simple :)
    // For internationalisation example see above code in swift
    const NSRange range = NSMakeRange(8,12);

    // Create the attributed string (text + attributes)
    NSMutableAttributedString *attributedText =
      [[NSMutableAttributedString alloc] initWithString:text
                                             attributes:attrs];
    [attributedText setAttributes:subAttrs range:range];

    // Set it in our UILabel and we are done!
    [_label setAttributedText:attributedText];
} else {
    // iOS5 and below
    // Here we have some options too. The first one is to do something
    // less fancy and show it just as plain text without attributes.
    // The second is to use CoreText and get similar results with a bit
    // more of code. Interested people please look down the old answer.

    // Now I am just being lazy so :p
    [_label setText:text];
}

そこに良い入門ブログ投稿のカップルで、ここでみんなからinvasivecodeのより多くの例の使用を説明NSAttributedStringのために見て、「iOSの6のためのNSAttributedStringの概要」「Interface Builderを使用したiOSの属性付き文字列 :)

PS:コードの上では動作するはずですが、脳でコンパイルされました。私はそれで十分だと思います:)


iOS5以前の古い回答

CATextLayerを使用するをしてください!2つのUILabelsよりもはるかに軽量でシンプルです。(iOS 3.2以降)

例。

QuartzCoreフレームワーク(CALayersに必要)、およびCoreText(属性付き文字列に必要)を追加することを忘れないでください。

#import <QuartzCore/QuartzCore.h>
#import <CoreText/CoreText.h>

以下の例では、ナビゲーションコントローラーのツールバーにサブレイヤーを追加します。iPhoneのàla Mail.app。:)

- (void)setRefreshDate:(NSDate *)aDate
{
    [aDate retain];
    [refreshDate release];
    refreshDate = aDate;

    if (refreshDate) {

        /* Create the text for the text layer*/    
        NSDateFormatter *df = [[NSDateFormatter alloc] init];
        [df setDateFormat:@"MM/dd/yyyy hh:mm"];

        NSString *dateString = [df stringFromDate:refreshDate];
        NSString *prefix = NSLocalizedString(@"Updated", nil);
        NSString *text = [NSString stringWithFormat:@"%@: %@",prefix, dateString];
        [df release];

        /* Create the text layer on demand */
        if (!_textLayer) {
            _textLayer = [[CATextLayer alloc] init];
            //_textLayer.font = [UIFont boldSystemFontOfSize:13].fontName; // not needed since `string` property will be an NSAttributedString
            _textLayer.backgroundColor = [UIColor clearColor].CGColor;
            _textLayer.wrapped = NO;
            CALayer *layer = self.navigationController.toolbar.layer; //self is a view controller contained by a navigation controller
            _textLayer.frame = CGRectMake((layer.bounds.size.width-180)/2 + 10, (layer.bounds.size.height-30)/2 + 10, 180, 30);
            _textLayer.contentsScale = [[UIScreen mainScreen] scale]; // looks nice in retina displays too :)
            _textLayer.alignmentMode = kCAAlignmentCenter;
            [layer addSublayer:_textLayer];
        }

        /* Create the attributes (for the attributed string) */
        CGFloat fontSize = 13;
        UIFont *boldFont = [UIFont boldSystemFontOfSize:fontSize];
        CTFontRef ctBoldFont = CTFontCreateWithName((CFStringRef)boldFont.fontName, boldFont.pointSize, NULL);
        UIFont *font = [UIFont systemFontOfSize:13];
        CTFontRef ctFont = CTFontCreateWithName((CFStringRef)font.fontName, font.pointSize, NULL);
        CGColorRef cgColor = [UIColor whiteColor].CGColor;
        NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                    (id)ctBoldFont, (id)kCTFontAttributeName,
                                    cgColor, (id)kCTForegroundColorAttributeName, nil];
        CFRelease(ctBoldFont);
        NSDictionary *subAttributes = [NSDictionary dictionaryWithObjectsAndKeys:(id)ctFont, (id)kCTFontAttributeName, nil];
        CFRelease(ctFont);

        /* Create the attributed string (text + attributes) */
        NSMutableAttributedString *attrStr = [[NSMutableAttributedString alloc] initWithString:text attributes:attributes];
        [attrStr addAttributes:subAttributes range:NSMakeRange(prefix.length, 12)]; //12 is the length of " MM/dd/yyyy/ "

        /* Set the attributes string in the text layer :) */
        _textLayer.string = attrStr;
        [attrStr release];

        _textLayer.opacity = 1.0;
    } else {
        _textLayer.opacity = 0.0;
        _textLayer.string = nil;
    }
}

この例では、2種類のフォント(太字と標準)しかありませんが、フォントサイズ、色、斜体、下線などが異なる場合もあります。NSAttributedString / NSMutableAttributedStringおよびCoreText属性文字列キーを見てください

それが役に立てば幸い


2
残念ながら、これ(および他の回答)は国際化対応ではありません。AndroidのようなHTMLタグのサポート(<b>、<i>)は素晴らしいと思います。
ビクターG

1
これは一例なので、私はそのことを処理しないことを望みました。ローカライズが必要な場合は、NSDateから日付コンポーネントを取得し、プログラムで適切な太字/太字以外の範囲を見つけることができます(範囲をハードコーディングする代わりに、ハードコーディングは理想的ではないという上記のコードにコメントがあります)
nacho4d

1
コードでは、より読みやすいObjective-Cリテラルを使用することを検討してください。たとえばに[NSDictionary dictionaryWithObjectsAndKeys: boldFont, NSFontAttributeName, foregroundColor, NSForegroundColorAttributeName, nil]なり@{ NSFontAttributeName: boldFont, NSForegroundColorAttributeName: foregroundColor }ます。
PatrickNLT 2015

@ nacho4d素晴らしい!ただし、タイプミスがあります。構文には中括弧({)ではなく中括弧()が必要[です。
PatrickNLT 2015

国際化対応のアプローチを示すコードをいくつか追加しました
nacho4d

85

UILabelでカテゴリを試してください:

使用方法は次のとおりです。

myLabel.text = @"Updated: 2012/10/14 21:59 PM";
[myLabel boldSubstring: @"Updated:"];
[myLabel boldSubstring: @"21:59 PM"];

そして、これがカテゴリーです

UILabel + Boldify.h

- (void) boldSubstring: (NSString*) substring;
- (void) boldRange: (NSRange) range;

UILabel + Boldify.m

- (void) boldRange: (NSRange) range {
    if (![self respondsToSelector:@selector(setAttributedText:)]) {
        return;
    }
    NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithAttributedString:self.attributedText];
    [attributedText setAttributes:@{NSFontAttributeName:[UIFont boldSystemFontOfSize:self.font.pointSize]} range:range];

    self.attributedText = attributedText;    
}

- (void) boldSubstring: (NSString*) substring {
    NSRange range = [self.text rangeOfString:substring];
    [self boldRange:range];
}

これはiOS 6以降でのみ機能することに注意してください。iOS 5以前では無視されます。


2
素敵なカテゴリー。それはフォントを太字にしませんが。そうするために、@{NSFontAttributeName:[UIFont boldSystemFontOfSize:self.font.pointSize]}あなたはそれをそのようにするべきでした:私は賛成しました
Lonkly

1
:あなたのラベルのフォントは、システムフォントでない場合は、変更する必要がある[UIFont boldSystemFontOfSize:self.font.pointSize]TO[UIFont fontWithName:self.font.fontName size:self.font.pointSize]
リー

48

これはInterface Builderで簡単に実行できます。

1)作るUILabelが 起因属性インスペクタ

太字の例ステップ1

2)太字にしたいフレーズの一部を選択します

太字の例ステップ2

3)フォントセレクタでフォント(または同じフォントの太字)を変更する

太字の例手順3

それで全部です!


これは、下線などの他の属性を適用するためではなく、太字(および他のフォントタイプ)に対してのみ実行できるように見えますか?(フォントピッカーにはこれらがありますが、下線はグレー表示されています)同じ動作が表示されますか?
pj4533 2014年

2
静的テキストの場合はそのように見えますが、この投稿を読む前に、これはとにかくわかりません。
preetam

この新しいInterface Builder機能に対する私の懸念は、システムフォントではなく、特定のカスタムフォントを選択せざるを得なくなることです。
Litome、

1
テキストの一部を太字にしたところ、属性インスペクターではどのように表示され、シミュレーターやストーリーボードでは表示されないかがわかります。
Besat 2017年

45

bbrameのカテゴリに基づくカテゴリがあります。これは同様に機能しますがUILabel、累積結果を使用して同じものを複数回太字にすることができます。

UILabel + Boldify.h

@interface UILabel (Boldify)
- (void) boldSubstring: (NSString*) substring;
- (void) boldRange: (NSRange) range;
@end

UILabel + Boldify.m

@implementation UILabel (Boldify)
- (void)boldRange:(NSRange)range {
    if (![self respondsToSelector:@selector(setAttributedText:)]) {
        return;
    }
    NSMutableAttributedString *attributedText;
    if (!self.attributedText) {
        attributedText = [[NSMutableAttributedString alloc] initWithString:self.text];
    } else {
        attributedText = [[NSMutableAttributedString alloc] initWithAttributedString:self.attributedText];
    }
    [attributedText setAttributes:@{NSFontAttributeName:[UIFont boldSystemFontOfSize:self.font.pointSize]} range:range];
    self.attributedText = attributedText;
}

- (void)boldSubstring:(NSString*)substring {
    NSRange range = [self.text rangeOfString:substring];
    [self boldRange:range];
}
@end

この修正により、次のように複数回使用できます。

myLabel.text = @"Updated: 2012/10/14 21:59 PM";
[myLabel boldSubstring: @"Updated:"];
[myLabel boldSubstring: @"21:59 PM"];

更新日: 2012/10/14 21:59 PM」と表示されます。


クレイジー、それは最後の部分文字列のみ、つまり21:59 PMのみを太字にします。
Prajeet Shrestha 2014

私は一年前にそれをテストしました、そしてそれはその時に機能するようでした。私の投稿の要点は、複数のボールドを処理するようにbbrameのカテゴリを変更することでした。現時点ではできませんが、2週間以内にこのコードを再テストして、機能することを確認します。
クレイジーヨーグルト2014

クレイジーはplz以下の私の答えを確認してください。そして、それを再利用可能にする方法を提案してください。
Prajeet Shrestha 2014

27

それは私のために働きました:

CGFloat boldTextFontSize = 17.0f;

myLabel.text = [NSString stringWithFormat:@"%@ 2012/10/14 %@",@"Updated:",@"21:59 PM"];

NSRange range1 = [myLabel.text rangeOfString:@"Updated:"];
NSRange range2 = [myLabel.text rangeOfString:@"21:59 PM"];

NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:myLabel.text];

[attributedText setAttributes:@{NSFontAttributeName:[UIFont boldSystemFontOfSize:boldTextFontSize]}
                        range:range1];
[attributedText setAttributes:@{NSFontAttributeName:[UIFont boldSystemFontOfSize:boldTextFontSize]}
                        range:range2];

myLabel.attributedText = attributedText;

Swiftバージョンの場合:ここを参照してください


美しくシンプル!ありがとうございました!
モナ

25

私はSwiftの拡張機能に対するCrazy Yoghurtの回答を採用しました。

extension UILabel {

    func boldRange(_ range: Range<String.Index>) {
        if let text = self.attributedText {
            let attr = NSMutableAttributedString(attributedString: text)
            let start = text.string.characters.distance(from: text.string.startIndex, to: range.lowerBound)
            let length = text.string.characters.distance(from: range.lowerBound, to: range.upperBound)
            attr.addAttributes([NSFontAttributeName: UIFont.boldSystemFont(ofSize: self.font.pointSize)], range: NSMakeRange(start, length))
            self.attributedText = attr
        }
    }

    func boldSubstring(_ substr: String) {
        if let text = self.attributedText {
            var range = text.string.range(of: substr)
            let attr = NSMutableAttributedString(attributedString: text)
            while range != nil {
                let start = text.string.characters.distance(from: text.string.startIndex, to: range!.lowerBound)
                let length = text.string.characters.distance(from: range!.lowerBound, to: range!.upperBound)
                var nsRange = NSMakeRange(start, length)
                let font = attr.attribute(NSFontAttributeName, at: start, effectiveRange: &nsRange) as! UIFont
                if !font.fontDescriptor.symbolicTraits.contains(.traitBold) {
                    break
                }
                range = text.string.range(of: substr, options: NSString.CompareOptions.literal, range: range!.upperBound..<text.string.endIndex, locale: nil)
            }
            if let r = range {
                boldRange(r)
            }
        }
    }
}

RangeとNSRangeの間の変換が良くないかもしれませんが、私はもっと良いものを見つけられませんでした。


1
本当にありがとう!まさに私が必要としたもの!私は中二行目を変更boldSubstring(_:)するvar range = text.string.range(of: substr, options: .caseInsensitive)別の大文字と小文字の文字列にも太字にします。
fl034

21

TTTAttributedLabelを確認してください。NSAttributedStringをそのラベルのテキストとして設定することで、1つのラベルにフォントと色を混在させることができるUILabelのドロップイン代替品です。


5
代わりのドロップを使用することに同意しました(いくつかあります)。Appleはまだこのようなものについての作業をまだ完了していない。アカデミックな演習以外では、この混乱を理解して実装することは本当に価値があるとは思いません-とにかく、すべてが次のリリース(またはそれ以降)でうまく整理されるでしょう。:) github.com/AliSoftware/OHAttributedLabel
トラッパー

@trapper-あなたはこのリンクで私の日を救った... +1000!
ダック

OHAttributedLabelもお勧めします。文字列では、<b>や<u>などのHTMLタグを直接使用できます。
RyanG 2013

12

この場合、あなたは試すことができます、

UILabel *displayLabel = [[UILabel alloc] initWithFrame:/*label frame*/];
displayLabel.font = [UIFont boldSystemFontOfSize:/*bold font size*/];

NSMutableAttributedString *notifyingStr = [[NSMutableAttributedString alloc] initWithString:@"Updated: 2012/10/14 21:59 PM"];
[notifyingStr beginEditing];
[notifyingStr addAttribute:NSFontAttributeName
                     value:[UIFont systemFontOfSize:/*normal font size*/]
                     range:NSMakeRange(8,10)/*range of normal string, e.g. 2012/10/14*/];
[notifyingStr endEditing];

displayLabel.attributedText = notifyingStr; // or [displayLabel setAttributedText: notifyingStr];

PS最初に値をラベルに割り当てます(例:displayLabel.text = @ "Updated:2013/12/23 21:59 PM";)
Mazen Kasser

8

UILabelでテキストを下線と同様に太字にします。コードに次の行を追加するだけです。

NSRange range1 = [lblTermsAndCondition.text rangeOfString:NSLocalizedString(@"bold_terms", @"")];
NSRange range2 = [lblTermsAndCondition.text rangeOfString:NSLocalizedString(@"bold_policy", @"")];
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:lblTermsAndCondition.text];
[attributedText setAttributes:@{NSFontAttributeName:[UIFont fontWithName:fontBold size:12.0]}
                        range:range1];
[attributedText setAttributes:@{NSFontAttributeName:[UIFont fontWithName:fontBold size:12.0]}
                        range:range2];


[attributedText addAttribute:(NSString*)kCTUnderlineStyleAttributeName
                  value:[NSNumber numberWithInt:kCTUnderlineStyleSingle]
                  range:range1];

[attributedText addAttribute:(NSString*)kCTUnderlineStyleAttributeName
                       value:[NSNumber numberWithInt:kCTUnderlineStyleSingle]
                       range:range2];



lblTermsAndCondition.attributedText = attributedText;

5

以下のコードを使用してください。お役に立てば幸いです。

NSString *needToChangeStr=@"BOOK";
NSString *display_string=[NSString stringWithFormat:@"This is %@",book];

NSMutableAttributedString *attri_str=[[NSMutableAttributedString alloc]initWithString:display_string];

int begin=[display_string length]-[needToChangeStr length];
int end=[needToChangeStr length];


[attri_str addAttribute:NSFontAttributeName value:[UIFont fontWithName:@"HelveticaNeue-Bold" size:30] range:NSMakeRange(begin, end)];

4

スウィフト4:

// attribute with color red and Bold
var attrs1 = [NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: 20), NSAttributedStringKey.foregroundColor: UIColor.red]

// attribute with color black and Non Bold
var attrs2 = [NSAttributedStringKey.font: UIFont(name: "Roboto-Regular", size: 20), NSAttributedStringKey.foregroundColor: UIColor.black]  

var color1 = NSAttributedString(string: "RED", attributes: attrs1)

var color2 = NSAttributedString(string: " BLACK", attributes: attrs2)

var string = NSMutableAttributedString()

string.append(color1)

string.append(color2)

// print the text with **RED** BLACK
print("Final String : \(string)")

3

これがあなたのニーズを満たすことを願っています。入力として処理する文字列を入力し、太字/色付きにする必要がある単語を入力として指定します。

func attributedString(parentString:String, arrayOfStringToProcess:[String], color:UIColor) -> NSAttributedString
{
    let parentAttributedString = NSMutableAttributedString(string:parentString, attributes:nil)
    let parentStringWords = parentAttributedString.string.components(separatedBy: " ")
    if parentStringWords.count != 0
    {
        let wordSearchArray = arrayOfStringToProcess.filter { inputArrayIndex in
            parentStringWords.contains(where: { $0 == inputArrayIndex }
            )}
        for eachWord in wordSearchArray
        {
            parentString.enumerateSubstrings(in: parentString.startIndex..<parentString.endIndex, options: .byWords)
            {
                (substring, substringRange, _, _) in
                if substring == eachWord
                {
                    parentAttributedString.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: 15), range: NSRange(substringRange, in: parentString))
                    parentAttributedString.addAttribute(.foregroundColor, value: color, range: NSRange(substringRange, in: parentString))
                }
            }
        }
    }
    return parentAttributedString
}

ありがとうございました。ハッピーコーディング。


2

私のプロジェクト(Swift)に実装した次のコードでNSRangeは必要ありません。

    //Code sets label (yourLabel)'s text to "Tap and hold(BOLD) button to start recording."
    let boldAttribute = [
        //You can add as many attributes as you want here.
        NSFontAttributeName: UIFont(name: "HelveticaNeue-Bold", size: 18.0)!]

    let regularAttribute = [
        NSFontAttributeName: UIFont(name: "HelveticaNeue-Light", size: 18.0)!]

    let beginningAttributedString = NSAttributedString(string: "Tap and ", attributes: regularAttribute )
    let boldAttributedString = NSAttributedString(string: "hold ", attributes: boldAttribute)
    let endAttributedString = NSAttributedString(string: "button to start recording.", attributes: regularAttribute )
    let fullString =  NSMutableAttributedString()

    fullString.appendAttributedString(beginningAttributedString)
    fullString.appendAttributedString(boldAttributedString)
    fullString.appendAttributedString(endAttributedString)

    yourLabel.attributedText = fullString

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.