You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:34:51