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

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

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

アプリをストアに公開した後、ユーザー層をさらに広げるための次のステップは国際化です。世界中の20カ国以上、そして多くの人々が右横書き(RTL)言語を使用しています。そのため、彼らのためにアプリをRTLに対応させることは必要不可欠です。

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

これには、RNで使われているコアレイアウトエンジンであるcss-layoutやRNのコア実装、そして特定のOSS JSコンポーネントをRTLに対応させるための変更が含まれています。

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

RNにおけるRTLサポートの変更点概要

css-layoutには、レイアウトのstartendという概念が既に存在します。左横書き(LTR)レイアウトでは、startleftを、endrightを意味します。しかし、RTLではstartrightを、endleftを意味します。これは、RNがstartendの計算に依存して、positionpaddingmarginを含む正しいレイアウトを計算できることを意味します。

加えて、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コアコードレベルではサポートされておらず、コンポーネントレベルでサポートされています。幸いなことに、SwipeableRowNavigationExperimentalなど、これらのコンポーネントの一部は既にRTLをサポートしています。しかし、ジェスチャーを持つ他のコンポーネントは手動で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サポートをより開発者フレンドリーにする方法を見つけることが理想的です。

試してみましょう!

RNTester内のRTLExampleをチェックして、RTLサポートについてさらに理解を深め、どのように機能したかをお知らせください!

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