2025-08-14 14:06:35 +08:00
|
|
|
|
# 统一文本尺寸计算实现
|
|
|
|
|
|
|
|
|
|
|
|
## 概述
|
|
|
|
|
|
|
|
|
|
|
|
本次修改统一了应用中的文本尺寸计算方法,解决了阿拉伯文本显示问题,提高了 RTL(从右到左)文本的渲染精度。
|
|
|
|
|
|
|
|
|
|
|
|
## 主要修改
|
|
|
|
|
|
|
|
|
|
|
|
### 1. XPNetImageYYLabel.m
|
|
|
|
|
|
|
|
|
|
|
|
**修改前:**
|
|
|
|
|
|
- 使用条件分支:RTL 文本使用 `boundingRectWithSize`,非 RTL 文本使用 `YYTextLayout`
|
|
|
|
|
|
- 导致 RTL 文本计算不准确
|
|
|
|
|
|
|
|
|
|
|
|
**修改后:**
|
|
|
|
|
|
- 统一使用 `YYTextLayout` 进行所有文本尺寸计算
|
|
|
|
|
|
- 新增 `createTextContainerForText:` 方法,根据文本方向配置容器
|
|
|
|
|
|
- RTL 文本使用 `YYTextTruncationTypeStart`,LTR 文本使用 `YYTextTruncationTypeEnd`
|
|
|
|
|
|
|
|
|
|
|
|
### 2. XPMessageInfoModel.m
|
|
|
|
|
|
|
|
|
|
|
|
**修改前:**
|
|
|
|
|
|
- 检测到阿拉伯字符时额外增加 20 点高度
|
|
|
|
|
|
- 可能导致高度计算不准确
|
|
|
|
|
|
|
|
|
|
|
|
**修改后:**
|
|
|
|
|
|
- 移除额外的阿拉伯文本高度调整
|
|
|
|
|
|
- 优化 `YYTextContainer` 配置,根据文本方向设置截断类型
|
|
|
|
|
|
- 依赖 `YYTextLayout` 的精确计算
|
|
|
|
|
|
|
|
|
|
|
|
### 3. 新增测试文件
|
|
|
|
|
|
|
|
|
|
|
|
- `XPTextLayoutTest.h/m`:提供测试方法验证修改效果
|
|
|
|
|
|
- 包含纯阿拉伯文本、混合文本、长文本的测试用例
|
|
|
|
|
|
|
|
|
|
|
|
## 技术细节
|
|
|
|
|
|
|
|
|
|
|
|
### YYTextContainer 配置
|
|
|
|
|
|
|
|
|
|
|
|
```objc
|
|
|
|
|
|
- (YYTextContainer *)createTextContainerForText:(NSAttributedString *)text {
|
|
|
|
|
|
YYTextContainer *container = [YYTextContainer new];
|
|
|
|
|
|
container.size = CGSizeMake(kRoomMessageMaxWidth, MAXFLOAT);
|
|
|
|
|
|
|
|
|
|
|
|
// 根据文本方向配置容器
|
|
|
|
|
|
if (isMSRTL()) {
|
|
|
|
|
|
container.truncationType = YYTextTruncationTypeStart;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
container.truncationType = YYTextTruncationTypeEnd;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return container;
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 统一计算逻辑
|
|
|
|
|
|
|
|
|
|
|
|
```objc
|
|
|
|
|
|
- (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. **性能**:避免重复计算和额外的高度调整
|
|
|
|
|
|
|
|
|
|
|
|
## 测试
|
|
|
|
|
|
|
|
|
|
|
|
运行测试验证修改效果:
|
|
|
|
|
|
|
|
|
|
|
|
```objc
|
|
|
|
|
|
#import "XPTextLayoutTest.h"
|
|
|
|
|
|
|
|
|
|
|
|
// 在适当的地方调用
|
|
|
|
|
|
[XPTextLayoutTest runAllTests];
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 注意事项
|
|
|
|
|
|
|
|
|
|
|
|
1. 确保 `YYText` 库版本支持所需功能
|
|
|
|
|
|
2. 测试各种文本场景,特别是长文本和混合文本
|
|
|
|
|
|
3. 验证在不同设备和系统版本上的表现
|
|
|
|
|
|
4. 关注性能影响,特别是在大量文本的场景下
|
|
|
|
|
|
|
|
|
|
|
|
## 后续优化建议
|
|
|
|
|
|
|
|
|
|
|
|
1. **字体优化**:为阿拉伯文本自动选择合适的字体(如 "GeezaPro")
|
|
|
|
|
|
2. **缓存机制**:为频繁计算的文本添加缓存
|
|
|
|
|
|
3. **性能监控**:添加性能指标监控文本计算耗时
|
|
|
|
|
|
4. **更多测试**:增加边界情况和性能测试
|
|
|
|
|
|
|
2025-08-14 17:56:56 +08:00
|
|
|
|
## 问题修复记录
|
|
|
|
|
|
|
|
|
|
|
|
### 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` 创建方法
|
|
|
|
|
|
```objc
|
|
|
|
|
|
// 错误的方式
|
|
|
|
|
|
YYTextLayout *layout = [YYTextLayout layoutWithContainerSize:maxSize text:attributedTextCopy];
|
|
|
|
|
|
|
|
|
|
|
|
// 正确的方式
|
|
|
|
|
|
YYTextLayout *layout = [YYTextLayout layoutWithContainer:container text:attributedTextCopy];
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
- **问题2 (第62行)**: 容器尺寸设置不准确
|
|
|
|
|
|
```objc
|
|
|
|
|
|
// 错误:使用计算出的size.width
|
|
|
|
|
|
container.size = CGSizeMake(size.width, MAXFLOAT);
|
|
|
|
|
|
|
|
|
|
|
|
// 正确:使用统一的最大宽度
|
|
|
|
|
|
container.size = CGSizeMake(kRoomMessageMaxWidth, MAXFLOAT);
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 2. XPMessageInfoModel.m 中的问题
|
|
|
|
|
|
- **问题3 (第36-38行)**: 多余的 `boundingRectWithSize` 调用
|
|
|
|
|
|
```objc
|
|
|
|
|
|
// 错误:存在未使用的计算,浪费性能
|
|
|
|
|
|
CGSize size = [content boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX)
|
|
|
|
|
|
options:NSStringDrawingUsesFontLeading | NSStringDrawingUsesLineFragmentOrigin
|
|
|
|
|
|
context:nil].size;
|
|
|
|
|
|
// 后续使用 YYTextLayout 计算,size 变量未被使用
|
|
|
|
|
|
|
|
|
|
|
|
// 正确:移除多余调用,统一使用 YYTextLayout
|
|
|
|
|
|
// 直接使用 YYTextLayout 进行所有文本尺寸计算
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 3. XPRoomMessageTableViewCell.m 中的问题
|
|
|
|
|
|
- **问题5 (第178行)**: 错误的宽度约束设置
|
|
|
|
|
|
```objc
|
|
|
|
|
|
// 错误:使用textBoundingSize.width作为宽度约束可能导致多行文本显示不完整
|
|
|
|
|
|
make.width.mas_lessThanOrEqualTo(size.width).priority(UILayoutPriorityDefaultHigh);
|
|
|
|
|
|
|
|
|
|
|
|
// 正确:移除此约束,让Label根据preferredMaxLayoutWidth自然确定宽度
|
|
|
|
|
|
// 保留trailing约束来限制最大宽度即可
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 修复内容
|
|
|
|
|
|
|
|
|
|
|
|
1. **修复 YYTextLayout 创建方式**: 改用 `layoutWithContainer:text:` 方法,确保 `maximumNumberOfRows=0` 和 `truncationType` 设置生效
|
|
|
|
|
|
|
|
|
|
|
|
2. **统一容器尺寸设置**: 在所有地方都使用 `kRoomMessageMaxWidth - 24` 作为容器宽度,正确处理 contentLabel 边距
|
|
|
|
|
|
|
|
|
|
|
|
3. **移除冗余计算**: 移除 `XPMessageInfoModel.m` 中未使用的 `boundingRectWithSize` 调用,提高性能并避免混淆
|
|
|
|
|
|
|
|
|
|
|
|
4. **优化外部约束逻辑**: 移除基于 `textBoundingSize.width` 的宽度约束,避免约束冲突和多行文本显示不完整
|
|
|
|
|
|
|
|
|
|
|
|
5. **修复边距计算**: 文本容器宽度减去 contentLabel 的左右边距(UIEdgeInsetsMake(4, 12, 4, 12) 中的各12px)
|
|
|
|
|
|
|
|
|
|
|
|
### 预期效果
|
|
|
|
|
|
|
|
|
|
|
|
- ✅ 多行文本能够完整显示
|
|
|
|
|
|
- ✅ 支持多语言文本布局(阿拉伯语RTL、中文、英文、土耳其语等)
|
|
|
|
|
|
- ✅ 统一的文本布局策略
|
|
|
|
|
|
- ✅ 提高文本尺寸计算的准确性和性能
|
|
|
|
|
|
- ✅ 避免约束冲突导致的布局异常
|
2025-08-14 18:04:38 +08:00
|
|
|
|
- ✅ 修复 preferredMaxLayoutWidth 与文本容器宽度不一致导致的截断问题
|
2025-08-14 17:56:56 +08:00
|
|
|
|
|
2025-08-14 14:06:35 +08:00
|
|
|
|
## 风险评估
|
|
|
|
|
|
|
|
|
|
|
|
- **低风险**:核心逻辑修改,但使用成熟的 `YYTextLayout`
|
|
|
|
|
|
- **兼容性**:保持现有 API 不变
|
|
|
|
|
|
- **回滚**:如有问题可快速回滚到原有逻辑
|