メインコンテンツへスキップ

React Native アプリの右から左へのレイアウトサポート

·7分で読めます
Mengjue (Mandy) Wang
Facebookのソフトウェアエンジニアインターン

アプリをアプリストアに公開した後、国際化はさらにオーディエンスリーチを拡大するための次のステップです。世界中の20か国以上、多くの人々が右から左(RTL)言語を使用しています。したがって、アプリでRTLをサポートすることが必要になります。

React NativeがRTLレイアウトをサポートするように改善されたことをお知らせします。これは現在、react-nativeのmasterブランチで利用可能であり、次のRC:v0.33.0-rcで利用可能になります。

これには、RNで使用されるコアレイアウトエンジンであるcss-layoutと、RNコア実装、およびRTLをサポートするための特定のOSS JSコンポーネントの変更が含まれていました。

本番環境でのRTLサポートをテストするために、最新バージョンのFacebook広告マネージャーアプリ(最初のクロスプラットフォーム100%RNアプリ)が、iOSAndroidの両方でアラビア語とヘブライ語でRTLレイアウトで利用可能になりました。これらのRTL言語での表示は次のようになります。

RTLサポートのためのRNの変更の概要

css-layoutには、すでにレイアウトのstartendの概念があります。左から右(LTR)レイアウトでは、startleftを意味し、endrightを意味します。しかし、RTLでは、startrightを意味し、endleftを意味します。これは、RNがstartendの計算に依存して、positionpadding、およびmarginを含む正しいレイアウトを計算できることを意味します。

さらに、css-layoutは、各コンポーネントの方向を親から継承するように既に設定しています。つまり、ルートコンポーネントの方向をRTLに設定するだけで、アプリ全体が反転します。

以下の図は、高レベルでの変更点を示しています。

これらには以下が含まれます。

この更新により、アプリでRTLレイアウトを許可すると

  • すべてのコンポーネントレイアウトが水平方向に反転します
  • RTL対応のOSSコンポーネントを使用している場合、一部のジェスチャーとアニメーションは自動的にRTLレイアウトになります
  • アプリを完全にRTL対応にするには、最小限の追加作業が必要になる場合があります

アプリをRTL対応にする

  1. RTLをサポートするには、まずRTL言語バンドルをアプリに追加する必要があります。

    • iOSAndroidの一般的なガイドを参照してください。
  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には、アプリのレイアウトがRTLかどうかを判別する定数isRTLがあり、レイアウトに応じて必要な変更を行うことができます。

方向の意味を持つアイコン

コンポーネントにアイコンまたは画像がある場合、RNはソース画像を反転しないため、LTRレイアウトとRTLレイアウトで同じように表示されます。したがって、レイアウトスタイルに従って反転する必要があります。

  • 左から右へのレイアウト
  • 右から左へのレイアウト

以下に、アイコンを方向に応じて反転させる2つの方法を示します。

  • 画像コンポーネントに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は、テストデバイスの言語を変更せずにRTLテストを高速化するためのforceRTL()関数を提供します。アプリにこのための簡単なスイッチを提供したい場合があります。以下は、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は画面上で「左」になります。製品コードをあまり変更する必要がないため、これは便利ですが、コード内で「真の左」または「真の右」を指定する方法がないことを意味します。将来的には、言語に関係なく、コンポーネントがその方向を制御できるようにする必要があるかもしれません。

  • ジェスチャーとアニメーションのRTLサポートをより開発者フレンドリーにする

    現在、ジェスチャーとアニメーションをRTL互換にするには、まだプログラミングの労力が必要です。将来的には、ジェスチャーとアニメーションのRTLサポートをより開発者フレンドリーにする方法を見つけるのが理想的でしょう。

試してみよう!

RTLサポートについてさらに理解するには、RNTesterRTLExampleをチェックして、それがどのように機能するかをお知らせください。

最後に、お読みいただきありがとうございます!React NativeのRTLサポートが、国際的なオーディエンス向けにアプリを成長させるのに役立つことを願っています!