跳到主要内容

React Native 应用的从右到左布局支持

·7 分钟阅读
Mengjue (Mandy) Wang
Facebook 软件工程师实习生

在应用商店发布应用后,国际化是进一步扩大受众范围的下一步。全球有 20 多个国家和无数人使用从右到左 (RTL) 的语言。因此,使你的应用支持 RTL 对他们来说是必要的。

我们很高兴地宣布 React Native 已经改进以支持 RTL 布局。这现在已经在今天的 react-native master 分支中可用,并将在下一个 RC 版本中提供:v0.33.0-rc

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

为了在生产环境中测试 RTL 支持,最新版本的 Facebook 广告管理工具 应用(第一个跨平台 100% RN 应用)现在以阿拉伯语和希伯来语提供,为 iOSAndroid 提供 RTL 布局。以下是其在这些 RTL 语言中的外观

RN 中 RTL 支持的概览更改

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

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

下图描述了高级别的更改

这些包括

通过此更新,当你允许你的应用使用 RTL 布局时

  • 每个组件布局都将水平翻转
  • 如果你正在使用支持 RTL 的 OSS 组件,则某些手势和动画将自动具有 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 布局中将以相同的方式显示,因为 RN 不会翻转你的源图像。因此,你应该根据布局样式翻转它们。

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

以下是根据方向翻转图标的两种方法

  • 向图像组件添加 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 布局相反。目前,在 RN 中,手势和动画在 RN 核心代码级别上不受支持,而是在组件级别上受支持。好消息是,其中一些组件今天已经支持 RTL,例如 SwipeableRowNavigationExperimental。但是,其他带有手势的组件将需要手动支持 RTL。

一个说明手势 RTL 支持的好例子是 SwipeableRow

手势示例
// 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 支持应涵盖你的应用中的大多数 UX;但是,目前存在一些局限性

  • 文本对齐行为在 Android 和 iOS 中有所不同
    • 在 iOS 中,默认文本对齐方式取决于活动的语言包,它们始终在同一侧。在 Android 中,默认文本对齐方式取决于文本内容的语言,即英语将左对齐,阿拉伯语将右对齐。
    • 理论上,这应该在跨平台之间保持一致,但是当使用应用时,有些人可能更喜欢一种行为而不是另一种行为。可能需要更多的用户体验研究来找出文本对齐的最佳实践。
  • 没有“真正的”左/右

    如前所述,我们将 JS 端的 left/right 样式映射到 start/end,RTL 布局的所有代码中的 left 在屏幕上变为“right”,而代码中的 right 在屏幕上变为“left”。这很方便,因为你无需过多更改产品代码,但这意味着无法在代码中指定“真正的左”或“真正的右”。将来,允许组件控制其方向而与语言无关可能是必要的。

  • 使手势和动画的 RTL 支持对开发者更友好

    目前,使手势和动画与 RTL 兼容仍然需要一些编程工作。将来,理想的情况是找到一种使手势和动画 RTL 支持对开发者更友好的方法。

尝试一下!

查看 RNTester 中的 RTLExample,以了解有关 RTL 支持的更多信息,并让我们知道它对你来说效果如何!

最后,感谢你的阅读!我们希望 React Native 的 RTL 支持能帮助你为国际受众扩展你的应用!