问题背景

项目里有一类问题只在小米 13 上出现:

  • 导航栏标题是很短的文本,例如 测试1设备4设定1
  • 在页面正文里展示正常
  • 但放到 Header 中后,会被错误显示成 测...设...

这类问题如果只做局部兼容,会在后续其他组件里重复出现,所以这次目标不是“修一个点”,而是找到可复用的根因和通用规则。

初始现象

最早怀疑过几个方向:

  • 业务页面额外加了 paddingmaxWidth
  • CKHeader 左右区域占位过宽
  • CKText 在 Android 上的字体设置
  • React Navigation Header 的标题容器布局
  • numberOfLines={1} 的单行省略逻辑

但在设备设置页中,只传 centerText: '测试1' 也能稳定复现,所以问题并不只存在于某个业务页面。

实验目标

为了缩小范围,在 TextMeasureTestScreen/index.tsx 中逐层做对照实验,验证以下问题:

  1. 是不是普通 Text 本身的问题
  2. 是不是 Animated.View / Animated.Text 的问题
  3. 是不是 @react-navigation/elementsHeaderTitle 问题
  4. 是不是 Header 组合布局的问题
  5. 是不是“自动宽度测量”导致的

第一层实验:普通 Text / CKText

实验内容:

  • 原生 Text
  • CKText
  • 不同 fontWeight
  • 文本包括:
    • 测试1
    • 设备4
    • 中文数字123
    • 设备名称中文+数字格式123

实验结果:

  • 测试1 正常
  • 设备4 正常
  • 中文数字123 正常
  • 只有明显超长的文本才会正常省略

结论:

  • 不是普通 Text 本身的问题
  • 不是 CKText 本身的问题
  • 不是“小米 13 上所有中文+数字文本都会异常”

第二层实验:Animated 最小实验

实验内容:

  • Text + View
  • Text + Animated.View
  • Animated.Text + View
  • Animated.Text + Animated.View

实验结果:

  • 四组都正常

结论:

  • 不是 Animated.View 单独导致的问题
  • 不是 Animated.Text 单独导致的问题

第三层实验:React Navigation Elements

实验内容:

  • HeaderTitle
  • Header

实验结果:

  • HeaderTitle 正常
  • Header 异常

表现非常典型:

  • 测试1 -> 测...
  • 设备4 -> 设...
  • 设定1 -> 设...
  • 设备名称 往往正常

结论:

  • 不是 HeaderTitle 自身的问题
  • 问题出在 Header 的组合布局场景里

第四层实验:继续拆 Header 内部变量

进一步做了三组 Header clone:

  • 去掉 expand
  • 去掉 maxWidth
  • HeaderTitle 换成普通 Text

实验结果:

  • 三组都还是异常

结论:

  • 根因不是某一个具体实现细节,例如:
    • 不是 expand
    • 不是 maxWidth
    • 不是 HeaderTitle

而是更底层的布局模式问题。

第五层实验:验证“自动宽度测量”假设

继续保持 Header 三段式布局,只改标题区域的宽度策略:

  • 普通 Text + 固定宽度
  • 普通 Text + flex: 1 + width: 0
  • 普通 Text + 不省略
  • 字符类型对照

实验结果非常关键:

1. 标题给固定宽度,恢复正常

例如:

  • 测试1 正常
  • 设备4 正常
  • 设定1 正常

2. 标题给明确可分配宽度,也恢复正常

即:

titleContainer: {
  flex: 1,
  width: 0,
  minWidth: 0,
}

这组同样恢复正常。

3. 去掉省略后,仍然会少字

这点说明问题不只是 ellipsis,而是文本区域实际可用宽度本身就被错误测量了。

4. 字符类型对照结果

在同样布局下:

  • 设备名称 正常
  • 12345 正常
  • 测试12 异常
  • 测试AB12 异常

这说明问题对下面这类混排文本尤其敏感:

  • 中文 + 数字
  • 中文 + 字母数字

最终结论

这次问题的根因可以总结为:

在小米 13 上,React Native 横向布局中,如果单行文本依赖“自动宽度测量(auto width / intrinsic width)”来参与排版,且文本是中文与数字或字母数字混排,那么文本宽度可能会被错误测窄,导致短文本也出现异常截断。

再强调一遍,这次真正的问题不是:

  • 不是 CKHeader 专属问题
  • 不是 HeaderTitle 专属问题
  • 不是 Animated.Text 专属问题
  • 不是省略号逻辑本身的问题

而是:

  • 横向布局
  • 单行文本
  • 依赖自动宽度
  • 混排内容

这几个条件叠加后,在小米 13 上触发了宽度测量异常。

可推广的修复规则

后续凡是遇到这一类布局,不要再让标题区域依赖文本内容自动定宽,而是统一采用“明确宽度分配”的方案。

推荐规则如下:

titleContainer: {
  flex: 1,
  width: 0,
  minWidth: 0,
}

titleText: {
  textAlign: 'center',
}

如果是固定结构,也可以直接给固定宽度。

为什么 width: 0 很关键

在横向 row 布局里:

  • 只有 flex: 1 有时还会受内容固有宽度影响
  • width: 0 可以明确告诉布局系统:标题区域不要按内容测量初始宽度,而是按剩余空间重新分配
  • minWidth: 0 则避免某些机型或某些组件默认最小宽度导致无法正确收缩

对项目的实际意义

这次结论不是只用于 CKHeader

后续如果项目中有下面这类组件,都建议优先检查:

  • 左右按钮 + 中间标题 的 Header
  • 列表项里中间单行标题、左右两边有图标或按钮
  • 自定义导航栏
  • 顶部工具栏
  • 横向卡片标题栏

只要满足:

  • flexDirection: 'row'
  • 中间文本 numberOfLines={1}
  • 文本可能出现中文+数字混排
  • 文本区域没有明确宽度策略

就有机会踩到同类问题。

推荐排查顺序

以后如果再遇到类似问题,建议按下面顺序排查:

  1. 先把同样文本放到固定宽度盒子里测试
  2. 再把同样文本放到当前横向布局里测试
  3. 如果固定宽度正常、横向布局异常,优先怀疑 auto width
  4. 给文本容器加:
flex: 1,
width: 0,
minWidth: 0
  1. 再观察是否恢复正常

最后总结

这次问题最终不是“某一个组件写错了”,而是找到了一条可复用的布局规则:

在 Android,尤其小米 13 上,横向布局中的单行混排文本不要依赖自动宽度测量;要给文本容器明确的宽度分配策略。

更多推荐