Files
peko-ios/YuMi/Modules/YMRoom/View/MessageContainerView/UNIFIED_TEXT_LAYOUT_README.md

7.0 KiB
Raw Blame History

统一文本尺寸计算实现

概述

本次修改统一了应用中的文本尺寸计算方法,解决了阿拉伯文本显示问题,提高了 RTL从右到左文本的渲染精度。

主要修改

1. XPNetImageYYLabel.m

修改前:

  • 使用条件分支RTL 文本使用 boundingRectWithSize,非 RTL 文本使用 YYTextLayout
  • 导致 RTL 文本计算不准确

修改后:

  • 统一使用 YYTextLayout 进行所有文本尺寸计算
  • 新增 createTextContainerForText: 方法,根据文本方向配置容器
  • RTL 文本使用 YYTextTruncationTypeStartLTR 文本使用 YYTextTruncationTypeEnd

2. XPMessageInfoModel.m

修改前:

  • 检测到阿拉伯字符时额外增加 20 点高度
  • 可能导致高度计算不准确

修改后:

  • 移除额外的阿拉伯文本高度调整
  • 优化 YYTextContainer 配置,根据文本方向设置截断类型
  • 依赖 YYTextLayout 的精确计算

3. 新增测试文件

  • XPTextLayoutTest.h/m:提供测试方法验证修改效果
  • 包含纯阿拉伯文本、混合文本、长文本的测试用例

技术细节

YYTextContainer 配置

- (YYTextContainer *)createTextContainerForText:(NSAttributedString *)text {
    YYTextContainer *container = [YYTextContainer new];
    container.size = CGSizeMake(kRoomMessageMaxWidth, MAXFLOAT);
    
    // 根据文本方向配置容器
    if (isMSRTL()) {
        container.truncationType = YYTextTruncationTypeStart;
    } else {
        container.truncationType = YYTextTruncationTypeEnd;
    }
    
    return container;
}

统一计算逻辑

- (void)updateLayoutWithAttributedText:(NSAttributedString *)attributedText {
    // 统一使用 YYTextLayout 进行文本尺寸计算
    YYTextContainer *container = [self createTextContainerForText:attributedText];
    YYTextLayout *layout = [YYTextLayout layoutWithContainer:container text:attributedText];
    CGSize finalSize = layout.textBoundingSize;
    
    if (self.updateLayoutSize) {
        self.updateLayoutSize(finalSize);
    }
}

优势

  1. 精确性YYTextLayout 对复杂文本(包括 RTL有更好的支持
  2. 一致性:统一的计算方法确保所有文本类型的一致性
  3. 可维护性:减少条件分支,代码更简洁
  4. 性能:避免重复计算和额外的高度调整

测试

运行测试验证修改效果:

#import "XPTextLayoutTest.h"

// 在适当的地方调用
[XPTextLayoutTest runAllTests];

注意事项

  1. 确保 YYText 库版本支持所需功能
  2. 测试各种文本场景,特别是长文本和混合文本
  3. 验证在不同设备和系统版本上的表现
  4. 关注性能影响,特别是在大量文本的场景下

后续优化建议

  1. 字体优化:为阿拉伯文本自动选择合适的字体(如 "GeezaPro"
  2. 缓存机制:为频繁计算的文本添加缓存
  3. 性能监控:添加性能指标监控文本计算耗时
  4. 更多测试:增加边界情况和性能测试

问题修复记录

2025-08-14 修复文本截断问题

问题描述:

  • 阿拉伯语正常显示,但其他语言(中文/英文/土耳其文)可能出现显示不全尾截断情况

根本原因:

  1. XPNetImageYYLabel.m 中的 setAttributedText 方法缺少 maximumNumberOfRows = 0 设置
  2. 截断类型配置不一致,部分地方硬编码为 YYTextTruncationTypeEnd

修复方案:

  1. createTextContainerForText 方法中添加 container.maximumNumberOfRows = 0
  2. setAttributedText 方法中统一文本方向配置逻辑
  3. 确保所有 YYTextContainer 都正确设置 maximumNumberOfRows = 0

修复后效果:

  • 所有语言的长文本都能完整显示,不会被意外截断
  • 保持阿拉伯语的正确显示效果
  • 统一了文本容器的配置逻辑

多行文本显示问题修复 (2024-01-XX)

问题描述

在聊天室消息显示中发现多行文本无法完整显示的问题,特别是包含多语言内容(阿拉伯语、中文、英文、土耳其语等)的长文本消息。

发现的问题

1. XPNetImageYYLabel.m 中的问题

  • 问题1 (第71行): 使用了错误的 YYTextLayout 创建方法

    // 错误的方式
    YYTextLayout *layout = [YYTextLayout layoutWithContainerSize:maxSize text:attributedTextCopy];
    
    // 正确的方式
    YYTextLayout *layout = [YYTextLayout layoutWithContainer:container text:attributedTextCopy];
    
  • 问题2 (第62行): 容器尺寸设置不准确

    // 错误使用计算出的size.width
    container.size = CGSizeMake(size.width, MAXFLOAT);
    
    // 正确:使用统一的最大宽度
    container.size = CGSizeMake(kRoomMessageMaxWidth, MAXFLOAT);
    

2. XPMessageInfoModel.m 中的问题

  • 问题3 (第36-38行): 多余的 boundingRectWithSize 调用
    // 错误:存在未使用的计算,浪费性能
    CGSize size = [content boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX)
                                        options:NSStringDrawingUsesFontLeading | NSStringDrawingUsesLineFragmentOrigin
                                        context:nil].size;
    // 后续使用 YYTextLayout 计算size 变量未被使用
    
    // 正确:移除多余调用,统一使用 YYTextLayout
    // 直接使用 YYTextLayout 进行所有文本尺寸计算
    

3. XPRoomMessageTableViewCell.m 中的问题

  • 问题5 (第178行): 错误的宽度约束设置
    // 错误使用textBoundingSize.width作为宽度约束可能导致多行文本显示不完整
    make.width.mas_lessThanOrEqualTo(size.width).priority(UILayoutPriorityDefaultHigh);
    
    // 正确移除此约束让Label根据preferredMaxLayoutWidth自然确定宽度
    // 保留trailing约束来限制最大宽度即可
    

修复内容

  1. 修复 YYTextLayout 创建方式: 改用 layoutWithContainer:text: 方法,确保 maximumNumberOfRows=0truncationType 设置生效

  2. 统一容器尺寸设置: 在所有地方都使用 kRoomMessageMaxWidth - 24 作为容器宽度,正确处理 contentLabel 边距

  3. 移除冗余计算: 移除 XPMessageInfoModel.m 中未使用的 boundingRectWithSize 调用,提高性能并避免混淆

  4. 优化外部约束逻辑: 移除基于 textBoundingSize.width 的宽度约束,避免约束冲突和多行文本显示不完整

  5. 修复边距计算: 文本容器宽度减去 contentLabel 的左右边距UIEdgeInsetsMake(4, 12, 4, 12) 中的各12px

预期效果

  • 多行文本能够完整显示
  • 支持多语言文本布局阿拉伯语RTL、中文、英文、土耳其语等
  • 统一的文本布局策略
  • 提高文本尺寸计算的准确性和性能
  • 避免约束冲突导致的布局异常
  • 修复 preferredMaxLayoutWidth 与文本容器宽度不一致导致的截断问题

风险评估

  • 低风险:核心逻辑修改,但使用成熟的 YYTextLayout
  • 兼容性:保持现有 API 不变
  • 回滚:如有问题可快速回滚到原有逻辑