web-dev-qa-db-ja.com

UIButtonのタイトルラベルのワードラップとテールトランケーション

UIButtontitleLabelに対して、ワードラッピングとテールトランケーションを同時に有効にする必要があります。 numberOfLinesを0より大きい値に設定しても機能せず、テキストは1行にとどまります。

私はすでに周りを検索しましたが、解決策は見つかりませんでした。何か案が?

20
pt2ph8

私がこの質問を投稿したのと同じ日に、UIButtonUILabelの上にnumberOfLinesを3に設定して解決しました。より良いアイデアですが、明らかに他の解決策はありません。

4
pt2ph8

これはnot正しいです:

lblTemp.lineBreakMode = NSLineBreakByWordWrapping | NSLineBreakByTruncatingTail
lblTemp.numberOfLines = 0;

NSLineBreakModeはNSParagraphStyle.hで次のように定義されています。

typedef NS_ENUM(NSInteger, NSLineBreakMode) {       /* What to do with long lines */
    NSLineBreakByWordWrapping = 0,      /* Wrap at Word boundaries, default */
    NSLineBreakByCharWrapping,      /* Wrap at character boundaries */
    NSLineBreakByClipping,      /* Simply clip */
    NSLineBreakByTruncatingHead,    /* Truncate at head of line: "...wxyz" */
    NSLineBreakByTruncatingTail,    /* Truncate at tail of line: "abcd..." */
    NSLineBreakByTruncatingMiddle   /* Truncate middle of line:  "ab...yz" */
} NS_ENUM_AVAILABLE_IOS(6_0);

これはNS_OPTIONではなくNS_ENUMであるため、マスクとして使用するためのものではないことに注意してください。詳細は this を参照してください。

実際には、これらの定数に演算子を使用すると、マスクがNSLineBreakByTruncatingTailに一致します。

(NSLineBreakByWordWrapping | NSLineBreakByTruncatingTail) == 4
NSLineBreakByTruncatingTail == 4

私の知る限り、Core Textの最後の行を切り捨て、ワードラップも行います単純なCTFramesetterCreateWithAttributedString&CTFrameDraw APIでは行えません行ごとのレイアウトで行うことができますが、UILabelはこれを行う必要がありますやっている。

iOS 6では、NSStringDrawing.hで新しい描画APIを公開することにより、これを簡素化しています。

typedef NS_ENUM(NSInteger, NSStringDrawingOptions) {
    NSStringDrawingTruncatesLastVisibleLine = 1 << 5, // Truncates and adds the Ellipsis character to the last visible line if the text doesn't fit into the bounds specified. Ignored if NSStringDrawingUsesLineFragmentOrigin is not also set.
    NSStringDrawingUsesLineFragmentOrigin = 1 << 0, // The specified Origin is the line fragment Origin, not the base line Origin
    NSStringDrawingUsesFontLeading = 1 << 1, // Uses the font leading for calculating line heights
    NSStringDrawingUsesDeviceMetrics = 1 << 3, // Uses image glyph bounds instead of typographic bounds
} NS_ENUM_AVAILABLE_IOS(6_0);

@interface NSAttributedString (NSExtendedStringDrawing)
- (void)drawWithRect:(CGRect)rect options:(NSStringDrawingOptions)options context:(NSStringDrawingContext *)context NS_AVAILABLE_IOS(6_0);
- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options context:(NSStringDrawingContext *)context NS_AVAILABLE_IOS(6_0);
@end

したがって、UILabelを使用している場合は、NSAttributedStringのNSParagraphStyleまたはラベル自体のlineBreakModeを次のように設定する必要があります。

NSLineBreakByTruncatingTail

ラベルのnumberOfLinesプロパティmustを0に設定します。

NumberOfLinesのUILabelヘッダーから:

// if the height of the text reaches the # of lines or the height of the view is less than the # of lines allowed, the text will be
// truncated using the line break mode.

UILabelドキュメントから:

This property controls the maximum number of lines to use in order to fit the label’s text into its bounding rectangle. The default value for this property is 1. To remove any maximum limit, and use as many lines as needed, set the value of this property to 0.
If you constrain your text using this property, any text that does not fit within the maximum number of lines and inside the bounding rectangle of the label is truncated using the appropriate line break mode.

UILabelのこのややあいまいな機能で発生する唯一の問題は、オンザフライでNSAttributedStringのNSParagraphStyleを変更しない限り、描画前にサイズを取得できないことです(これは一部のUITableView + UITableViewCell動的レイアウトに必要です)。

IOS 6.1.4以降では、NSLineBreakByTruncatingTail改行モード(UILabelの場合)を持つNSAttributedStringで-boundingRectWithSize:options:contextを呼び出すと、次のオプションが渡された場合でも誤った1行の高さを返します

(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine)

(NSStringDrawingUsesLineFragmentOriginは複数行の文字列に必要であることに注意してください。)

さらに悪いことに、UILabelのlineBreakModeはnot NSAttributedStrings段落スタイルをオーバーライドするため、サイズ設定計算のために属性付き文字列の段落スタイルを変更し、後でUILabelに渡して描画できるようにする必要があります。 。

つまり、NSLabelの-boundingRectWithSize:options:contextとNSLineBreakByTruncatingTailのNSLineBreakByWordWrapping(そうすることで、内部でNSStringDrawingTruncatesLastVisibleLineを使用するか、最後の行をクリップするために何でもする)

文字列の段落スタイルを2回以上変更したくない場合の唯一の代替策は、-drawRect:をオーバーライドするシンプルなUIViewサブクラスを実行し、適切なcontentModeを再描画に設定して、iOS 6の新しい描画APIを使用することです。 :

- (void)drawWithRect:(CGRect)rect options:(NSStringDrawingOptions)options context:(NSStringDrawingContext *)context NS_AVAILABLE_IOS(6_0);

忘れずにNSLineBreakByWordWrappingを使用し、オプションとして(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine)を渡します。

最後に、iOS 6より前では、属性付き文字列に対してWordの折り返し+末尾の切り捨てを行う場合は、Core Textを使用して行ごとのレイアウトを自分で行う必要がありました。

41
Marc Etcheverry
[self.costomButton.titleLabel setTextAlignment:UITextAlignmentLeft];
[self.costomButton.titleLabel setNumberOfLines:3];

最初にAlignmentを設定する必要があります。これは、システムのバージョンが5.0よりも大きい場合にのみ機能します。

4
akin
button.titleLabel.numberOfLines = 2;
button.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
UIFont * theFont = [UIFont systemFontOfSize: 14]; // you set
CGSize textSize = [titleStr sizeWithAttributes:@{NSFontAttributeName: theFont}];
CGFloat theWidth = kScreenWidth-otherWidthYouSet;// I thought the button's frame is content driving ,and is limited 
CGFloat ratio = theWidth*heightYouSet/((textSize.width+4)*(textSize.height+6));// 4 , 6 , is made by experience . I think the textSize is taken one line text default by the system 
NSUInteger validNum = ratio * titleStr.length;

if(ratio<1){
    [button setTitle: [[titleStr substringToIndex: validNum] stringByAppendingString: @"..."] state: yourState];

}
else{
    [button setTitle: titleStr state: yourState];
}
0
dengApro

Swift 5:

"numberOfLines = 2"と "lineBreakMode"を "truncate tail"にUILabelに設定するだけで、複数の行をテールトランケーションとともに使用できます。

enter image description here

0
Smit Yash

NumberOfLinesを2以上に設定してみて、それに応じて高さも設定してください。

    m_button = [UIButton buttonWithType:UIButtonTypeCustom];
[m_button setFrame:CGRectMake(isLandscape?20:10, 40, isLandscape?300:250, 40)];
m_button.titleLabel.font  = [UIFont fontWithName:@"HelveticaNeue" size:17];
[m_btnDiscoverPoint setTitle:@"Title" forState:UIControlStateNormal];
CGRect buttonFrame = [m_button frame];

if ([m_button.titleLabel.text length]>0) {
    CGSize suggestedSize = [m_button.titleLabel.text sizeWithFont:[UIFont fontWithName:@"HelveticaNeue" size:17] constrainedToSize:CGSizeMake(FLT_MAX,m_button.frame.size.height) lineBreakMode:UILineBreakModeWordWrap];

    if (suggestedSize.width >= self.view.frame.size.width) {
        suggestedSize.width = self.view.frame.size.width-10;
        suggestedSize.height=suggestedSize.height+20;
        m_button.titleLabel.numberOfLines=2;
    }
    else{
        m_button.titleLabel.numberOfLines=1;
    }

    buttonFrame.size.width = suggestedSize.width;

    [m_button setFrame:buttonFrame];
}
[m_button setBackgroundColor:[UIColor clearColor]];
[m_button addTarget:self action:@selector(btnClickAction) forControlEvents:UIControlEventTouchUpInside];
0
Meet