如何在 React Native 中处理 Android 手机吞字问题

本文由 AI 协助更新

React Native App 在部分型号的 Android 手机上,可能会发生文字显示不全的问题。

2026-02-09 更新:重写 Text.render 的方式在高版本 ReactNative 已无效

下面采用 Babel 别名 + Proxy + Shim 组件 的方式,在任意 RN 版本下都能无侵入地修复该问题。

复现问题

作者在 React Native 0.67.4 环境下,编写了一个小 demo 来复现这个问题,如下:

function IncompleteText() {
  return (
    <View style={styles.container}>
      <View style={styles.row}>
        <Text style={styles.text}>我在左边 完整</Text>
        <Text style={styles.text}>我在右边 完整</Text>
      </View>
      <View style={styles.row}>
        <Text style={styles.text}>12345</Text>
        <Text style={styles.text}>67890</Text>
      </View>
      <View style={styles.row}>
        <Text style={styles.text}>abcd</Text>
        <Text style={styles.text}>efgh</Text>
      </View>
      <View style={styles.row}>
        <Text style={styles.text}>今年是 2022 年</Text>
        <Text style={styles.text}>亏了好多 ¥</Text>
      </View>
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  row: {
    marginTop: 16,
    marginHorizontal: 24,
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    height: 60,
    backgroundColor: '#f5f5f5',
  },
  text: {
    fontSize: 18,
    color: '#333333',
    fontWeight: 'normal',
    // fontFamily: 'DFWaWaSC-W5',
    backgroundColor: 'yellow',
  },
})

Text 中的文本同时符合以下两个条件时,在部分 Android 手机上会出现文字显示不全的问题。

  • 含有半角字符(数字、字母、空格、特殊符号)
  • style 设置了 fontWeight 属性,不管它的值是什么

譬如作者这台手机:

手机型号MIUI 版本Android 版本
MI 812.5.210

就会出现文字显示不全的问题,即使将 fontWeight 设置为 bold,也不会有粗体效果。

但是只要 style 设置了 fontFamily,就不会有显示不全的问题,因此,怎样才能正确地设置 fontFamily 呢?

解决问题

思路:用 Babel 的 module-resolver 把对 react-native 的引用指到我们自己的 proxy 文件;proxy 对 Text(以及可选的 ViewImage 等)返回 Shim 组件,Shim 内部再使用真实的 react-native 并注入默认 fontFamily。这样不依赖 RN 内部 Text.render,兼容从低版本到高版本的所有 RN。

1. 安装依赖

本方案依赖 Babel 的 module-resolver 插件做别名解析,需先安装(若已为其他 Shim 配过可跳过):

yarn add -D babel-plugin-module-resolver

2. Babel 配置

babel.config.jsmodule-resolver 里为 react-native 配置别名,指向项目中的 proxy 文件(路径按你项目结构调整,例如放在 app/utils/ 下):

// babel.config.js
module.exports = {
  presets: ['module:@react-native/babel-preset'],
  plugins: [
    [
      'module-resolver',
      {
        root: ['./'],
        extensions: ['.ts', '.tsx', '.ios.js', '.android.js', '.js', '.json'],
        alias: {
          '^react-native$': './app/utils/react-native-proxy.js', // 指向下面的 proxy 文件
          // ... 其他 alias
        },
      },
    ],
  ],
};

3. react-native-proxy.js

从真实 react-native 包做一层 Proxy,对 Text 返回我们的 TextShim,其余组件直接透传。这样业务里 import { Text } from 'react-native' 拿到的就是 Shim。

// app/utils/react-native-proxy.js(路径需与 babel alias 一致)
const RN = require('../../node_modules/react-native');

module.exports = new Proxy(RN, {
  get(target, prop) {
    if (prop === 'Text') {
      if (!module.exports.__TextShim) {
        module.exports.__TextShim = require('./shim/TextShim').default;
      }
      return module.exports.__TextShim;
    }
    return target[prop];
  },
});

若已按 无侵入增强 React Native 组件方案 配置了 proxy,可在此 proxy 里一起代理 ViewImage 等,同一套 proxy 即可。

4. TextShim 组件(解决吞字)

Shim 内只对 Android 合并默认 fontFamily,其它平台直接使用原生 Text

// app/utils/shim/TextShim.tsx
import React from 'react';
import type { TextProps } from 'react-native';

const RN = require('../../node_modules/react-native');

const defaultFontFamily = {
  ...RN.Platform.select({
    android: { fontFamily: '' },
  }),
};

const TextShim = (props: TextProps) => {
  const { style, ...rest } = props;
  if (RN.Platform.OS !== 'android') {
    return <RN.Text style={style} {...rest} />;
  }
  const flat = RN.StyleSheet.flatten(style) || {};
  return <RN.Text style={[defaultFontFamily, flat]} {...rest} />;
};

export default TextShim;

按需可在此 Shim 里再做 fontWeightfontFamily 的映射(例如项目中的 shim/font-helpers.ts),以同时解决粗体与吞字。

示例

这里有一个示例open in new window,供你参考。

上次更新: