Xamarin.iOS长文本处理:如何避免UILabel中间截断后省略号后出现字符
解决UILabel中间截断后省略号出现多余字符的问题
我之前也踩过这个坑!系统自带的MiddleTruncation(Swift里对应NSLineBreakMode.byTruncatingMiddle)在多行显示场景下,偶尔会因为文本布局计算的小误差,或是遇到特殊字符、emoji时,出现省略号后面跟着多余字符的情况。下面给你几个靠谱的解决办法:
方法一:手动实现中间截断逻辑
这种方法最可控,完全绕开系统的坑。核心思路是:先计算UILabel能容纳的最大文本范围,再手动截取开头和结尾的有效内容,中间用省略号拼接。
代码示例(Swift)
func truncateTextMiddle(for label: UILabel, fullText: String) -> String { guard label.numberOfLines > 0 else { return fullText } let font = label.font let maxSize = CGSize(width: label.bounds.width, height: CGFloat.greatestFiniteMagnitude) let ellipsis = "..." // 先计算省略号的尺寸 let ellipsisSize = ellipsis.size(withAttributes: [.font: font]) // 用二分法找到最合适的截取长度 var leftLength = 0 var rightLength = fullText.count var result = fullText while leftLength <= rightLength { let mid = (leftLength + rightLength) / 2 let leftPart = String(fullText.prefix(mid)) let rightPart = String(fullText.suffix(fullText.count - mid - ellipsis.count)) let testText = leftPart + ellipsis + rightPart let textSize = testText.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, attributes: [.font: font], context: nil).size if textSize.height <= label.bounds.height { result = testText leftLength = mid + 1 } else { rightLength = mid - 1 } } return result } // 使用方式 myLabel.text = truncateTextMiddle(for: myLabel, fullText: "你的超长文本内容") myLabel.lineBreakMode = .byWordWrapping // 不需要系统截断,用我们处理好的文本
代码示例(Objective-C)
- (NSString *)truncateTextMiddleForLabel:(UILabel *)label fullText:(NSString *)fullText { if (label.numberOfLines == 0) return fullText; UIFont *font = label.font; CGSize maxSize = CGSizeMake(label.bounds.size.width, CGFLOAT_MAX); NSString *ellipsis = @"…"; // 计算省略号的尺寸 CGSize ellipsisSize = [ellipsis sizeWithAttributes:@{NSFontAttributeName: font}]; NSInteger leftLength = 0; NSInteger rightLength = fullText.length; NSString *result = fullText; while (leftLength <= rightLength) { NSInteger mid = (leftLength + rightLength) / 2; NSString *leftPart = [fullText substringToIndex:mid]; NSString *rightPart = [fullText substringFromIndex:fullText.length - (rightLength - mid)]; NSString *testText = [NSString stringWithFormat:@"%@%@%@", leftPart, ellipsis, rightPart]; CGRect textRect = [testText boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: font} context:nil]; if (textRect.size.height <= label.bounds.size.height) { result = testText; leftLength = mid + 1; } else { rightLength = mid - 1; } } return result; } // 使用方式 myLabel.text = [self truncateTextMiddleForLabel:myLabel fullText:@"你的超长文本内容"]; myLabel.lineBreakMode = NSLineBreakByWordWrapping;
方法二:利用TextKit精确计算布局
如果需要处理富文本这类复杂场景,可以用TextKit模拟UILabel的布局,精准找到需要截断的位置:
- 创建
NSTextStorage、NSLayoutManager和NSTextContainer,复刻UILabel的布局规则 - 遍历布局后的每一行,定位中间需要截断的行
- 手动插入省略号并重新拼接文本
这种方法适合富文本场景,但代码量会相对大一些。
关键注意事项
- 一定要在UILabel的frame确定后再调用截断方法(比如在
viewDidLayoutSubviews里,而非viewDidLoad),否则宽度计算会出错 - 如果UILabel宽度会动态变化(比如自适应布局),要在布局更新后重新计算截断文本
内容的提问来源于stack exchange,提问作者Ranwala
相关产品推荐
相关产品推荐

