跳至主内容

为 React Native 应用提供从右到左布局支持

· 1 分钟阅读
Mengjue (Mandy) Wang
Facebook 软件工程实习生
非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

将应用发布到应用商店后,国际化是扩大受众范围的下一步。全球有超过 20 个国家和众多人口使用从右到左(RTL)的语言。因此,为这些用户提供 RTL 支持是必要的。

我们很高兴地宣布,React Native 已经改进以支持 RTL 布局。该功能现在已在 react-native 的主分支中提供,并将在下一个候选版本(RC)中发布:v0.33.0-rc

这涉及到更改 RN 使用的核心布局引擎 css-layout、RN 核心实现,以及特定的开源 JS 组件以支持 RTL。

为了在生产环境中测试 RTL 支持,最新版本的 Facebook Ads Manager 应用(首个跨平台 100% RN 应用)现已提供阿拉伯语和希伯来语的 RTL 布局,支持 iOSAndroid。以下是这些 RTL 语言下的效果:

RN 中支持 RTL 的更改概述

css-layout 的布局中已有 startend 的概念。在从左到右(LTR)布局中,start 表示 leftend 表示 right。但在 RTL 中,start 表示 rightend 表示 left。这意味着我们可以让 RN 依赖 startend 的计算来确定正确的布局,包括 positionpaddingmargin

此外,css-layout 已经让每个组件的方向继承自其父组件。这意味着,我们只需将根组件的方向设置为 RTL,整个应用就会翻转。

下图从高层次描述了这些更改:

这些更改包括:

通过此更新,当您为应用启用 RTL 布局时:

  • 每个组件的布局将水平翻转

  • 如果您使用的是支持 RTL 的开源组件,一些手势和动画将自动具有 RTL 布局

  • 只需极少的额外工作,即可让您的应用完全支持 RTL

让应用支持 RTL

  1. 要支持 RTL,首先需要将 RTL 语言包添加到应用中。

  2. 在你的应用原生代码起始处调用 allowRTL() 函数以启用 RTL 布局。我们提供此工具函数,确保仅在你的应用准备就绪时才应用 RTL 布局。示例如下:

    iOS:

    // in AppDelegate.m
    [[RCTI18nUtil sharedInstance] allowRTL:YES];

    Android:

    // in MainActivity.java
    I18nUtil sharedI18nUtilInstance = I18nUtil.getInstance();
    sharedI18nUtilInstance.allowRTL(context, true);
  3. 对于 Android 应用,你需要在 AndroidManifest.xml 文件的 <application> 元素中添加 android:supportsRtl="true" 属性。

现在,当你重新编译应用并将设备语言切换为 RTL 语言(如阿拉伯语或希伯来语)时,应用布局应会自动切换为 RTL 模式。

编写支持 RTL 的组件

通常情况下,大多数组件已原生支持 RTL 布局,例如:

  • 从左到右布局
  • 从右到左布局

但需要注意几种特殊情况,这时你需要使用 I18nManager。在 I18nManager 中,常量 isRTL 可判断当前布局是否为 RTL,从而进行相应调整。

具有方向含义的图标

当组件包含图标或图像时,它们在 LTR 和 RTL 布局中的显示方向不会自动改变。因此你需要根据布局手动调整方向:

  • 从左到右布局
  • 从右到左布局

以下两种方法可实现图标方向切换:

  • 为图像组件添加 transform 样式:

    <Image
    source={...}
    style={{transform: [{scaleX: I18nManager.isRTL ? -1 : 1}]}}
    />
  • 或根据布局方向切换图像源:

    let imageSource = require('./back.png');
    if (I18nManager.isRTL) {
    imageSource = require('./forward.png');
    }
    return <Image source={imageSource} />;

手势与动画

在 Android 和 iOS 开发中,切换到 RTL 布局时手势和动画方向与 LTR 相反。目前在 React Native 中,手势和动画的支持不在核心代码层,而是在组件层。好消息是部分组件(如 SwipeableRowNavigationExperimental)已支持 RTL 布局。但其他涉及手势的组件仍需手动适配。

SwipeableRow 是演示 RTL 手势支持的典型范例。

手势示例
// SwipeableRow.js
_isSwipingExcessivelyRightFromClosedPosition(gestureState: Object): boolean {
// ...
const gestureStateDx = IS_RTL ? -gestureState.dx : gestureState.dx;
return (
this._isSwipingRightFromClosed(gestureState) &&
gestureStateDx > RIGHT_SWIPE_THRESHOLD
);
},
动画示例
// SwipeableRow.js
_animateBounceBack(duration: number): void {
// ...
const swipeBounceBackDistance = IS_RTL ?
-RIGHT_SWIPE_BOUNCE_BACK_DISTANCE :
RIGHT_SWIPE_BOUNCE_BACK_DISTANCE;
this._animateTo(
-swipeBounceBackDistance,
duration,
this._animateToClosedPositionDuringBounce,
);
},

维护 RTL 应用

即使在初始发布 RTL 兼容应用后,您仍可能需要迭代新功能。为提高开发效率,I18nManager 提供了 forceRTL() 函数,无需更改测试设备语言即可快速进行 RTL 测试。您可以在应用中添加简单的切换开关实现此功能。以下是 RNTester 中 RTL 示例的参考实现:

<RNTesterBlock title={'Quickly Test RTL Layout'}>
<View style={styles.flexDirectionRow}>
<Text style={styles.switchRowTextView}>forceRTL</Text>
<View style={styles.switchRowSwitchView}>
<Switch
onValueChange={this._onDirectionChange}
style={styles.rightAlignStyle}
value={this.state.isRTL}
/>
</View>
</View>
</RNTesterBlock>;

_onDirectionChange = () => {
I18nManager.forceRTL(!this.state.isRTL);
this.setState({isRTL: !this.state.isRTL});
Alert.alert(
'Reload this page',
'Please reload this page to change the UI direction! ' +
'All examples in this app will be affected. ' +
'Check them out to see what they look like in RTL layout.',
);
};

开发新功能时,您可以轻松切换此按钮并重新加载应用查看 RTL 布局。这样做的好处是无需更改语言设置即可测试,但如下一节所述,某些文本对齐方式不会自动改变。因此建议在正式发布前使用 RTL 语言全面测试应用。

限制与未来计划

RTL 支持已覆盖应用中的大部分用户体验,但目前仍存在以下限制:

  • 文本对齐行为在 Android 和 iOS 上存在差异
    • iOS 中默认文本对齐取决于活动语言包,始终位于固定侧。Android 中则取决于文本内容的语言,例如英语左对齐而阿拉伯语右对齐
    • 理论上应保持跨平台一致性,但用户可能偏好不同对齐方式。需更多用户体验研究确定最佳实践
  • 不存在"绝对左/右"定位

    如前所述,我们将 JS 端的 left/right 样式映射为 start/end,导致 RTL 布局中代码的 left 实际显示为"右",right 显示为"左"。这减少了代码修改量,但也意味着无法在代码中指定"绝对左侧"或"绝对右侧"。未来可能需要支持组件独立控制布局方向。

  • 提升手势和动画的 RTL 开发体验

    当前实现手势和动画的 RTL 兼容性仍需较多编程工作。未来将探索更友好的开发方案。

立即尝试!

查看 RNTester 中的 RTLExample 深入了解 RTL 支持,欢迎反馈使用体验!

最后,感谢您的阅读!希望 React Native 的 RTL 支持能帮助您拓展国际用户群体!