2014-07-16 70 views
4

我使用一个表视图来显示书籍的列表,其中每个单元都有一个UILabel显示书的名字和另一个UILabel的节目本书的作者(S)截断的UILabel在特定位置

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

  • 如果本书有一个作者(“约翰·科尔曼”)标签应该是:“约翰·科尔曼”
  • 如果书有超过一个作者('约翰科尔曼','鲍勃之夜','迈克尔')的标签应该是:“约翰科尔曼+2作者”

现在的问题是这样的,我想标签被截断' +”。因此,举例来说,如果第一作者的名字很长,可以说,“本杰明·沃尔特·杰克逊,我想在标签看起来像这样:

"Benjamin Walter Ja... +2 authors" 

课程的默认行为截断到底标签,所以它看起来是这样的:

"Benjamin Walter Jackson +2 au..." 

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

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

+0

嗯也许最简单的方法是使用2个标签。其中一个用于名称,另一个用于+2 ....因此,如果您的名字不适合,它会在...结束时得到...如果是这样,那么将第一个标签调整为字符串大小并移动第二个标签在第一个结尾。如果您以不同方式尝试,我会看到很多计算结果;) – AntonijoDev

回答

5

编辑:推广解决方案,以处理任何“截断位置”字符串。以前的版本仅在字符串@" +"的实例处截断。编辑允许您定义要截断的位置。


我把我的回答从this question(这是从回答修改于this site答案),并定制以满足您的需求。创建一个新的NSString界面,您可以在其中发送要自定义截断的字符串。

注意:此解决方案仅适用于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 
+0

感谢您的回复,我的解决方案只有一个问题,如果作者名称包含'+',该怎么办?字符串会被过早地截断,比 – Eyal

+0

我刚刚注意到你在你的评论中提到了这个,任何想法如何解决这个问题? – Eyal

+2

没关系通过做[truncatedString rangeOfString:@“+”options:NSBackwardsSearch]解决了它; – Eyal

0

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

编辑: 看看@ Stonz2回答

0

这个答案是基于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; 
} 

我创建了一个称为ResponsiveLabel一个UILabel子类,令牌处理定制截断以及应用样式像userhandles,网址,#标签等模式