ios UIButton 的标题标签自动换行,尾截断
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7378308/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
UIButton's Title Label Word Wrap with Tail Truncation
提问by pt2ph8
I need to enable word wrapping and tail truncation, at the same time, on a UIButton
's titleLabel
. Setting numberOfLines to something more than 0 doesn't work, the text stays on one line.
我需要启用自动换行和尾巴截断,在同一时间,在UIButton
的titleLabel
。将 numberOfLines 设置为大于 0 的值不起作用,文本保留在一行上。
I've already searched around and haven't found a solution. Any idea?
我已经四处搜索了,但没有找到解决方案。任何的想法?
采纳答案by pt2ph8
I solved it the same day I posted this question by putting a UIButton
on top of a UILabel
with numberOfLines
set to 3. I had left this unaccepted to see if someone had a better idea, but apparently there's no other solution.
我当天解决它我通过把一个张贴了这个问题UIButton
上的顶部UILabel
与numberOfLines
设置为3。我已经离开这个不被接受,看看是否有人有更好的主意,但显然没有其他解决办法。
回答by Marc Etcheverry
This is notcorrect:
这是不正确的:
lblTemp.lineBreakMode = NSLineBreakByWordWrapping | NSLineBreakByTruncatingTail
lblTemp.numberOfLines = 0;
NSLineBreakMode is defined in NSParagraphStyle.h as:
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);
Note that it is an NS_ENUM, not an NS_OPTION, so it is not meant to be used as a mask. For more information see this.
请注意,它是一个 NS_ENUM,而不是一个 NS_OPTION,因此它不打算用作掩码。有关更多信息,请参阅此。
In reality using the |operator on those constants leads to a mask matching NSLineBreakByTruncatingTail:
在现实中使用| 这些常量上的运算符导致匹配 NSLineBreakByTruncatingTail 的掩码:
(NSLineBreakByWordWrapping | NSLineBreakByTruncatingTail) == 4
NSLineBreakByTruncatingTail == 4
As far as I know, truncating the last line in Core Text and also doing word wrapping can not be done with the simple CTFramesetterCreateWithAttributedString & CTFrameDraw APIs, but can be done with line by line layout, which UILabel must be doing.
据我所知,截断 Core Text 中的最后一行并进行自动换行无法使用简单的 CTFramesetterCreateWithAttributedString & CTFrameDraw API来完成,但可以通过逐行布局来完成,而 UILabel 必须这样做。
iOS 6 simplifies this by exposing new drawing APIs in NSStringDrawing.h:
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
So if you are using UILabel, you want your NSAttributedString's NSParagraphStyle or the lineBreakMode on the label itself to be set to :
因此,如果您使用 UILabel,您希望将 NSAttributedString 的 NSParagraphStyle 或标签本身的 lineBreakMode 设置为:
NSLineBreakByTruncatingTail
And the numberOfLines property on the label mustbe set to 0.
并且标签上的 numberOfLines 属性必须设置为 0。
From the UILabel headers on numberOfLines:
从 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.
From the UILabel documentation:
从 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.
The only problem that arises with this somewhat obscure feature of UILabel is that you can not get the size before drawing (which is a necessity for some UITableView + UITableViewCell dynamic layouts) without resorting to modifying the NSAttributedString's NSParagraphStyle on the fly.
UILabel 的这个有点晦涩的特性带来的唯一问题是,如果不立即修改 NSAttributedString 的 NSParagraphStyle,就无法在绘制之前获得大小(这对于某些 UITableView + UITableViewCell 动态布局来说是必需的)。
As of iOS 6.1.4, calling -boundingRectWithSize:options:context with a NSAttributedString that has a NSLineBreakByTruncatingTail line break mode (for UILabel), returns an incorrect single line heighteven if the following options are passed in:
从 iOS 6.1.4 开始,使用具有 NSLineBreakByTruncatingTail 换行模式(对于 UILabel)的 NSAttributedString 调用 -boundingRectWithSize:options:context,即使传入以下选项,也会返回不正确的单行高度:
(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine)
(Please note that NSStringDrawingUsesLineFragmentOrigin is a necessity for multi line strings.)
(请注意 NSStringDrawingUsesLineFragmentOrigin 是多行字符串的必要条件。)
What is worse is that UILabel's lineBreakMode does notoverride the NSAttributedStrings paragraph style, so you have to modify your attributed string's paragraph style for your sizing calculation, and later for passing it to the UILabel so it can draw it.
更糟糕的是,UILabel的lineBreakMode并没有覆盖NSAttributedStrings段落样式,所以你必须修改你的属性串的段落样式为您的容量计算,后来因为它传递给的UILabel,因此可以借鉴它。
That is, NSLineBreakByWordWrapping for -boundingRectWithSize:options:context and NSLineBreakByTruncatingTail for the UILabel (so it can, use NSStringDrawingTruncatesLastVisibleLine internally, or whatever it does to clip the last line)
也就是说,NSLineBreakByWordWrapping 用于 UILabel 的 -boundingRectWithSize:options:context 和 NSLineBreakByTruncatingTail(因此它可以在内部使用 NSStringDrawingTruncatesLastVisibleLine,或者它所做的任何事情来剪辑最后一行)
The only alternative if you do not want to mutate your string's paragraph style more than once much would be to do a simple UIView subclass that overrides -drawRect: (with the appropriate contentMode set to redraw as well), and uses iOS 6's new drawing API:
如果您不想多次改变字符串的段落样式,唯一的选择是做一个简单的 UIView 子类来覆盖 -drawRect:(将适当的 contentMode 设置为重绘),并使用 iOS 6 的新绘图 API :
- (void)drawWithRect:(CGRect)rect options:(NSStringDrawingOptions)options context:(NSStringDrawingContext *)context NS_AVAILABLE_IOS(6_0);
Remembering to use NSLineBreakByWordWrapping and passing in (NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine) as the options.
记住使用 NSLineBreakByWordWrapping 并传入 (NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine) 作为选项。
Finally, before iOS 6, if you wanted to do word wrapping + tail truncation for an attributed string you would have to do line by line layout yourself with Core Text.
最后,在 iOS 6 之前,如果您想对属性字符串进行自动换行 + 尾部截断,您必须自己使用 Core Text 进行逐行布局。
回答by akin
[self.costomButton.titleLabel setTextAlignment:UITextAlignmentLeft];
[self.costomButton.titleLabel setNumberOfLines:3];
Be sure you should set Alignment
first
ps: this only work when the system version is bigger than 5.0
确保你应该Alignment
先设置ps:这仅在系统版本大于 5.0 时有效
回答by Meet
Try setting the numberOfLines more than 2, and set height also accordingly.
尝试将 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];
回答by dengApro
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];
}
回答by Smit Yash
回答by aZtraL-EnForceR
All UI properties are deprecated in iOS Use NS abbreviations instead of UI. As shown example here - NSLineBreakByTruncatingMiddle
iOS 中不推荐使用所有 UI 属性使用 NS 缩写而不是 UI。如此处所示的示例 -NSLineBreakByTruncatingMiddle
回答by charlesk
You can specify more than one lineBreakMode on a label by using the bitwise OR operator.
您可以使用按位 OR 运算符在标签上指定多个 lineBreakMode。
For example, the following code would wrap the text of the label, and would add the ellipsis on the tail end of the text when it expanded beyond the size of the label's frame height.
例如,以下代码将包装标签的文本,并在文本扩展到超出标签框架高度的大小时在文本的尾端添加省略号。
lblTemp.lineBreakMode = UILineBreakModeWordWrap | UILineBreakModeTailTruncation;
lblTemp.numberOfLines = 0;
UPDATE: this is not correct. It appears to work because UILineBreakModeWordWrap
is 0 in the enum. See comments below.
更新:这是不正确的。它似乎有效,因为UILineBreakModeWordWrap
枚举中的值为 0。请参阅下面的评论。