React Native 应用的从右到左布局支持
将应用程序发布到应用商店后,国际化是进一步扩大受众范围的下一步。全球有20多个国家和众多人口使用从右到左 (RTL) 语言。因此,让您的应用程序支持 RTL 对他们来说是必要的。
我们很高兴地宣布,React Native 已经改进以支持 RTL 布局。这现在已经在 react-native 的 master 分支中可用,并且将在下一个 RC 版本中提供:v0.33.0-rc
。
这涉及更改 RN 使用的核心布局引擎 css-layout、RN 核心实现以及特定的开源 JS 组件以支持 RTL。
为了在生产环境中对 RTL 支持进行实战测试,最新版本的 Facebook 广告管理工具应用程序(第一个100% RN 跨平台应用程序)现在支持阿拉伯语和希伯来语,并为 iOS 和 Android 提供 RTL 布局。以下是它在这些 RTL 语言中的样子:


RN 对 RTL 支持的总体变更
css-layout 已经有布局的 start
和 end
概念。在从左到右 (LTR) 布局中,start
意味着 left
,end
意味着 right
。但在 RTL 中,start
意味着 right
,end
意味着 left
。这意味着我们可以让 RN 依赖 start
和 end
的计算来计算正确的布局,其中包括 position
、padding
和 margin
。
此外,css-layout 已经使每个组件的方向都继承自其父组件。这意味着,我们只需将根组件的方向设置为 RTL,整个应用程序就会翻转。
下图描述了高层次的变化:
这包括:
- css-layout 对绝对定位的 RTL 支持
- 在 RN 核心实现中将
left
和right
映射到 shadow nodes 的start
和end
- 以及公开一个 桥接实用模块 以帮助控制 RTL 布局
通过此更新,当您允许您的应用程序使用 RTL 布局时:
- 每个组件布局将水平翻转
- 如果您使用支持 RTL 的开源组件,某些手势和动画将自动具有 RTL 布局
- 可能需要最少的额外努力才能使您的应用程序完全支持 RTL
让应用程序支持 RTL
-
为了支持 RTL,您应该首先将 RTL 语言包添加到您的应用程序中。
-
通过在原生代码开头调用
allowRTL()
函数来允许您的应用程序使用 RTL 布局。我们提供了此实用程序,以便仅在您的应用程序准备就绪时才应用 RTL 布局。这是一个示例:iOS
// in AppDelegate.m
[[RCTI18nUtil sharedInstance] allowRTL:YES];Android
// in MainActivity.java
I18nUtil sharedI18nUtilInstance = I18nUtil.getInstance();
sharedI18nUtilInstance.allowRTL(context, true); -
对于 Android,您需要将
android:supportsRtl="true"
添加到AndroidManifest.xml
文件中的<application>
元素中。
现在,当您重新编译应用程序并将设备语言更改为 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,例如 SwipeableRow
和 NavigationExperimental
。但是,其他带有手势的组件需要手动支持 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 支持应该涵盖您应用程序中的大部分用户体验;但是,目前存在一些限制:
- 文本对齐行为在 Android 和 iOS 中有所不同
- 在 iOS 中,默认文本对齐取决于活动的语言包,它们始终在一侧对齐。在 Android 中,默认文本对齐取决于文本内容的语言,即英语将左对齐,阿拉伯语将右对齐。
- 理论上,这应该在跨平台保持一致,但有些人在使用应用程序时可能更喜欢一种行为而不是另一种。可能需要更多的用户体验研究来找出文本对齐的最佳实践。
-
没有“真正的”左/右
如前所述,我们将 JS 端的
left
/right
样式映射到start
/end
,代码中所有 RTL 布局的left
在屏幕上都变为“右”,代码中的right
在屏幕上都变为“左”。这很方便,因为您不需要过多更改产品代码,但这意味着无法在代码中指定“真正的左”或“真正的右”。将来,允许组件控制其方向而不管语言如何可能是必要的。 -
使手势和动画的 RTL 支持更具开发人员友好性
目前,使手势和动画与 RTL 兼容仍需要一些编程工作。未来,理想的做法是找到一种方法,使手势和动画的 RTL 支持更具开发人员友好性。
试一试!
查看 RNTester
中的 RTLExample
以了解更多关于 RTL 支持的信息,并告诉我们它对您来说如何!
最后,感谢您的阅读!我们希望 React Native 对 RTL 的支持能帮助您为国际受众发展您的应用程序!