在特定位置截断UILabel

我使用表格视图来显示书籍列表,每个单元格都有一个显示书名的UILabel ,另一个显示书籍作者的UILabel

我的问题是关于作者的标签。 一本书可以有多个作者,我希望它的行为如下:

  • 如果书有一个作者('约翰·科尔曼')的标签应该是:“约翰·科尔曼”
  • 如果书中有多个作者('John Colman','Bob Night','Michael'),标签应该是:“John Colman +2名作者”

现在的问题是这个,我想要标签在“+”之前被截断。 例如,如果第一个作者的名字很长,让我们说“本杰明·沃尔特·jackson”(Benjamin Walter Jackson),我想要这样的标签:

 "Benjamin Walter Ja... +2 authors" 

当然,默认行为最终会截断标签,所以它看起来像这样:

 "Benjamin Walter Jackson +2 au..." 

如果我使用中间截断,没有承诺它会在正确的位置(在“+”之前)截断标签

我正在寻找一种方法来做到尽可能高效,而不会影响表视图的滚动性能。

编辑:通用的解决scheme,以处理任何“截断位置”string。 以前的版本仅在string@" +"实例处截断。 编辑允许你定义你想要截断的地方。


我从这个问题 (这是一个答案从本网站的答案修改)的答案,并根据您的需要量身定制。 创build一个新的NSString接口,你可以发送你的string被自定义截断。

注意:此解决scheme仅适用于iOS 7+。 要在iOS 6中使用,请在NSString + TruncateToWidth.m文件中使用sizeWithFont:而不是sizeWithAttributes:

的NSString + TruncateToWidth.h

 @interface NSString (TruncateToWidth) - (NSString*)stringByTruncatingAtString:(NSString *)string toWidth:(CGFloat)width withFont:(UIFont *)font; @end 

的NSString + TruncateToWidth.m

 #import "NSString+TruncateToWidth.h" #define ellipsis @"…" @implementation NSString (TruncateToWidth) - (NSString*)stringByTruncatingAtString:(NSString *)string toWidth:(CGFloat)width withFont:(UIFont *)font { // If the string is already short enough, or // if the 'truncation location' string doesn't exist // go ahead and pass the string back unmodified. if ([self sizeWithAttributes:@{NSFontAttributeName:font}].width < width || [self rangeOfString:string].location == NSNotFound) return self; // Create copy that will be the returned result NSMutableString *truncatedString = [self mutableCopy]; // Accommodate for ellipsis we'll tack on the beginning width -= [ellipsis sizeWithAttributes:@{NSFontAttributeName:font}].width; // Get range of the passed string. Note that this only works to the first instance found, // so if there are multiple, you need to modify your solution NSRange range = [truncatedString rangeOfString:string]; range.length = 1; while([truncatedString sizeWithAttributes:@{NSFontAttributeName:font}].width > width && range.location > 0) { range.location -= 1; [truncatedString deleteCharactersInRange:range]; } // Append ellipsis range.length = 0; [truncatedString replaceCharactersInRange:range withString:ellipsis]; return truncatedString; } @end 

使用它:

 // Make sure to import the header file where you want to use it myLabel.text = [@"Benjamin Walker Jackson + 2 authors" stringByTruncatingAtString:@" +" toWidth:myLabel.frame.size.width withFont:myLabel.font]; // Sample Result: Benjamin Walte... + 2 authors 

UILabel无法处理除iOS 7之外的截断函数。您应该根据固定长度(以uilabel字体大小计算)截断string,但这很头疼,或者您可以使用两个UILabel。 第一作者的第一uilabel固定大小。 它会自动截断在最后,因为你知道。 那么第二个uilabel应该与第一个标签的“+ 2其他作者”完全一致。

编辑:看看@ Stonz2的答案

这个答案是基于https://stackoverflow.com/a/30813691/2123122 。 这里是示例代码。

 @interface CustomLabel() @property (nonatomic, retain) NSLayoutManager *layoutManager; @property (nonatomic, retain) NSTextContainer *textContainer; @property (nonatomic, retain) NSTextStorage *textStorage; @end @implementation CustomLabel - (instancetype)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { [self configureTextkitStack]; } return self; } - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self configureTextkitStack]; } return self; } - (void)configureTextkitStack { _textContainer = [[NSTextContainer alloc] init]; _textContainer.lineFragmentPadding = 0; _textContainer.maximumNumberOfLines = self.numberOfLines; _textContainer.lineBreakMode = self.lineBreakMode; _textContainer.widthTracksTextView = YES; _layoutManager = [[NSLayoutManager alloc] init]; [_layoutManager addTextContainer:self.textContainer]; [_textContainer setLayoutManager:self.layoutManager]; _textStorage = [[NSTextStorage alloc] init]; [_textStorage addLayoutManager:self.layoutManager]; [self.layoutManager setTextStorage:_textStorage]; } - (NSRange)rangeForTokenInsertion { self.textContainer.size = self.bounds.size; if (self.attributedText.length > 0 ){ [self.textStorage setAttributedString:[[NSMutableAttributedString alloc]initWithAttributedString:self.attributedText]]; } if (self.text.length == 0) { return NSMakeRange(NSNotFound, 0); } NSInteger glyphIndex = [self.layoutManager glyphIndexForCharacterAtIndex:self.textStorage.length - 1]; NSRange range = [self.layoutManager truncatedGlyphRangeInLineFragmentForGlyphAtIndex:glyphIndex]; return range; } 

现在你可以使用这个如下:

  NSRange range = [self.label rangeForTokenInsertion]; NSString *token = @"...+2 authors"; if (range.location != NSNotFound ) { range.length += token.length; range.location -= token.length; } if (range.location != NSNotFound) { NSString *finalString = [self.label.text stringByReplacingCharactersInRange:range withString:token]; self.label.text = finalString; } 

我创build了一个名为ResponsiveLabel的UILabel子类,它处理自定义截断标记以及将样式应用到用户手柄,URL,标签等模式。