我使用表格视图来显示图书清单,其中每个单元格都有一个显示图书名称的UILabel
,另一个UILabel
显示图书的作者(S)
我的问题是作者标签。一本书可以有多位作者,我希望它表现如下:
现在的问题是,我希望标签在' +'之前被截断。因此,例如,如果第一作者姓名很长,那么就说“本杰明·沃尔特·杰克逊”,我希望标签看起来像这样:
"Benjamin Walter Ja... +2 authors"
默认行为当然会截断最后的标签,所以它看起来像这样:
"Benjamin Walter Jackson +2 au..."
如果我使用中间截断,则无法保证它会在正确的位置截断标签(在' +'之前)
我正在寻找一种尽可能高效的方法,而不会影响表格视图的滚动性能。
答案 0 :(得分: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
答案 1 :(得分:0)
UILabel除了在iOS 7之外无法处理这样的截断功能。要么你应该根据自己固定的(用uilabel字体大小计算)长度截断字符串,但这很令人头疼,或者你可以使用两个UILabel。第一作者的固定大小的第一uilabel。如你所知,它会在最后自动截断。然后第二个uilabel应该在第一个标签的右边用“+ 2个其他作者”绘制。
编辑: 看看@Stonz2回答
答案 2 :(得分: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子类,它处理自定义截断标记以及将样式应用于用户句柄,URL,主题标签等模式。