mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Updated docs for next
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<!DOCTYPE html><html><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><title>Right-to-Left Layout Support For React Native Apps – React Native | A framework for building native apps using React</title><meta name="viewport" content="width=device-width"><meta property="og:title" content="Right-to-Left Layout Support For React Native Apps – React Native | A framework for building native apps using React"><meta property="og:type" content="website"><meta property="og:url" content="http://facebook.github.io/react-native/index.html"><meta property="og:image" content="http://facebook.github.io/react-native/img/opengraph.png?2"><meta property="og:description" content="A framework for building native apps using React"><base href="/react-native/releases/next/"><link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.css"><link rel="shortcut icon" href="img/favicon.png?2"><link rel="stylesheet" href="css/react-native.css"><script type="text/javascript" src="//use.typekit.net/vqa1hcx.js"></script><script type="text/javascript">try{Typekit.load();}catch(e){}</script></head><body><div class="container"><div class="nav-main"><div class="wrap"><a class="nav-home" href=""><img src="img/header_logo.png">React Native</a><a class="nav-version" href="/react-native/versions.html">next</a><div class="nav-site-wrapper"><ul class="nav-site nav-site-internal"><li><a href="docs/getting-started.html" class="" data-target=".nav-docs">Docs</a></li><li><a href="support.html" class="">Support</a></li><li><a href="showcase.html" class="">Showcase</a></li><li><a href="blog/" class="active">Blog</a></li></ul><div class="algolia-search-wrapper"><input id="algolia-doc-search" tabindex="0" type="text" placeholder="Search docs..."></div><ul class="nav-site nav-site-external"><li><a href="https://github.com/facebook/react-native" class="">GitHub</a></li><li><a href="http://facebook.github.io/react" class="">React</a></li></ul></div></div></div><section class="content wrap documentationContent"><div class="nav-docs"><div class="nav-docs-section"><h3>Recent Posts</h3><ul><li><a class="active" href="/react-native/blog/2016/08/19/right-to-left-support-for-react-native-apps.html">Right-to-Left Layout Support For React Native Apps</a></li><li><a class="" href="/react-native/blog/2016/08/12/react-native-meetup-san-francisco.html">San Francisco Meetup Recap</a></li><li><a class="" href="/react-native/blog/2016/07/06/toward-better-documentation.html">Toward Better Documentation</a></li><li><a class="" href="/react-native/blog/2016/03/24/introducing-hot-reloading.html">Introducing Hot Reloading</a></li></ul></div></div><div class="inner-content"><div class="article"><h1>Right-to-Left Layout Support For React Native Apps</h1><p class="meta">August 19, 2016 by <a href="https://github.com/MengjueW" target="_blank">Mengjue (Mandy) Wang</a></p><hr><div><p>After launching an app to the app stores, internationalization is the next step to further your audience reach. Over 20 countries and numerous people around the world use Right-to-Left (RTL) languages. Thus, making your app RTL support for them is necessary.</p><p>We're glad to announce that React Native has been improved to support RTL layouts. This is now available in the <a href="https://github.com/facebook/react-native" target="_blank">react-native</a> master branch today, and will be available in the next RC: <a href="https://github.com/facebook/react-native/releases" target="_blank"><code>v0.33.0-rc</code></a>.</p><p>This involved changing <a href="https://github.com/facebook/css-layout" target="_blank">css-layout</a>, the core layout engine used by RN, and RN core implementation, as well as specific OSS JS components to support RTL.</p><p>To battle test the RTL support in production, the latest version of the <strong>Facebook Ads Manager</strong> app (the first cross-platform 100% RN app) is now available in Arabic and Hebrew with RTL layouts for both <a href="https://itunes.apple.com/app/id964397083" target="_blank">iOS</a> and <a href="https://play.google.com/store/apps/details?id=com.facebook.adsmanager" target="_blank">Android</a>. Here is how it looks like in those RTL languages:</p><span><p align="center">
|
||||
<img src="/react-native/blog/img/rtl-ama-ios-arabic.png" height="480" style="margin:25px">
|
||||
<img src="/react-native/blog/img/rtl-ama-android-hebrew.png" height="480" style="margin:25px">
|
||||
<img src="/react-native/blog/img/rtl-ama-ios-arabic.png" width="280" style="margin:10px">
|
||||
<img src="/react-native/blog/img/rtl-ama-android-hebrew.png" width="280" style="margin:10px">
|
||||
</p>
|
||||
|
||||
</span><h2><a class="anchor" name="overview-changes-in-rn-for-rtl-support"></a>Overview Changes in RN for RTL support <a class="hash-link" href="#overview-changes-in-rn-for-rtl-support">#</a></h2><p><a href="https://github.com/facebook/css-layout" target="_blank">css-layout</a> already has a concept of <code>start</code> and <code>end</code> for the layout. In the Left-to-Right (LTR) layout, <code>start</code> means <code>left</code>, and <code>end</code> means <code>right</code>. But in RTL, <code>start</code> means <code>right</code>, and <code>end</code> means <code>left</code>. This means we can make RN depend on the <code>start</code> and <code>end</code> calculation to compute the correct layout, which includes <code>position</code>, <code>padding</code>, and <code>margin</code>.</p><p>In addition, <a href="https://github.com/facebook/css-layout" target="_blank">css-layout</a> already makes each component's direction inherits from its parent. This means, we simply need to set the direction of the root component to RTL, and the entire app will flip.</p><p>The diagram below describes the changes at high level:</p><p><img src="/react-native/blog/img/rtl-rn-core-updates.png" alt=""></p><p>These include:
|
||||
@@ -16,12 +16,10 @@
|
||||
<img src="/react-native/blog/img/rtl-demo-listitem-rtl.png" width="300">
|
||||
</p>
|
||||
|
||||
</span></li></ul><p>However, there are several cases to be aware of, for which you will need the <a href="https://github.com/facebook/react-native/blob/f0fb228ec76ed49e6ed6d786d888e8113b8959a2/Libraries/Utilities/I18nManager.js" target="_blank"><code>I18nManager</code></a>. In <a href="https://github.com/facebook/react-native/blob/f0fb228ec76ed49e6ed6d786d888e8113b8959a2/Libraries/Utilities/I18nManager.js" target="_blank"><code>I18nManager</code></a>, there is a constant <code>isRTL</code> to tell if layout of app is RTL or not, so that you can make the necessary changes according to the layout.</p><h4><a class="anchor" name="icons-with-directional-meaning"></a>Icons with Directional Meaning <a class="hash-link" href="#icons-with-directional-meaning">#</a></h4><p>If your component has icons or images, they will be displayed the same way in LTR and RTL layout, because RN will not flip your source image. Therefore, you should flip them according to the layout style.
|
||||
* Left-to-Right Layout</p><span> <p align="left">
|
||||
<img src="/react-native/blog/img/rtl-demo-icon-ltr.png" width="300">
|
||||
</p>
|
||||
|
||||
</span><ul><li><p>Right-to-Left Layout</p><span><p align="left">
|
||||
</span></li></ul><p>However, there are several cases to be aware of, for which you will need the <a href="https://github.com/facebook/react-native/blob/f0fb228ec76ed49e6ed6d786d888e8113b8959a2/Libraries/Utilities/I18nManager.js" target="_blank"><code>I18nManager</code></a>. In <a href="https://github.com/facebook/react-native/blob/f0fb228ec76ed49e6ed6d786d888e8113b8959a2/Libraries/Utilities/I18nManager.js" target="_blank"><code>I18nManager</code></a>, there is a constant <code>isRTL</code> to tell if layout of app is RTL or not, so that you can make the necessary changes according to the layout.</p><h4><a class="anchor" name="icons-with-directional-meaning"></a>Icons with Directional Meaning <a class="hash-link" href="#icons-with-directional-meaning">#</a></h4><p>If your component has icons or images, they will be displayed the same way in LTR and RTL layout, because RN will not flip your source image. Therefore, you should flip them according to the layout style.</p><ul><li><p>Left-to-Right Layout</p><span><p align="left">
|
||||
<img src="/react-native/blog/img/rtl-demo-icon-ltr.png" width="300">
|
||||
</p>
|
||||
</span></li><li><p>Right-to-Left Layout</p><span><p align="left">
|
||||
<img src="/react-native/blog/img/rtl-demo-icon-rtl.png" width="300">
|
||||
</p>
|
||||
|
||||
@@ -35,12 +33,12 @@
|
||||
<span class="token keyword">return</span> <span class="token punctuation">(</span>
|
||||
<Image source<span class="token operator">=</span><span class="token punctuation">{</span>imageSource<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span>
|
||||
<span class="token punctuation">)</span><span class="token punctuation">;</span></div></li></ul><h4><a class="anchor" name="gestures-and-animations"></a>Gestures and Animations <a class="hash-link" href="#gestures-and-animations">#</a></h4><p>In iOS and Android development, when you change to RTL layout, the gestures and animations are the opposite of LTR layout. Currently, in RN, gestures and animations are not supported on RN core code level, but on components level. The good news is, some of these components already support RTL today, such as <a href="https://github.com/facebook/react-native/blob/38a6eec0db85a5204e85a9a92b4dee2db9641671/Libraries/Experimental/SwipeableRow/SwipeableRow.js" target="_blank"><code>SwipeableRow</code></a> and <a href="https://github.com/facebook/react-native/tree/master/Libraries/NavigationExperimental" target="_blank"><code>NavigationExperimental</code></a>. However, other components with gestures will need to support RTL manually.</p><p>A good example to illustrate gesture RTL support is <a href="https://github.com/facebook/react-native/blob/38a6eec0db85a5204e85a9a92b4dee2db9641671/Libraries/Experimental/SwipeableRow/SwipeableRow.js" target="_blank"><code>SwipeableRow</code></a>.</p><span><p align="center">
|
||||
<img src="/react-native/blog/img/rtl-demo-swipe-ltr.png" height="480" style="margin:25px">
|
||||
<img src="/react-native/blog/img/rtl-demo-swipe-rtl.png" height="480" style="margin:25px">
|
||||
<img src="/react-native/blog/img/rtl-demo-swipe-ltr.png" width="280" style="margin:10px">
|
||||
<img src="/react-native/blog/img/rtl-demo-swipe-rtl.png" width="280" style="margin:10px">
|
||||
</p>
|
||||
|
||||
|
||||
</span><h6><a class="anchor" name="gestures-example"></a>Gestures Example <a class="hash-link" href="#gestures-example">#</a></h6><div class="prism language-javascript"><span class="token comment" spellcheck="true">// SwipeableRow.js
|
||||
</span><h5><a class="anchor" name="gestures-example"></a>Gestures Example <a class="hash-link" href="#gestures-example">#</a></h5><div class="prism language-javascript"><span class="token comment" spellcheck="true">// SwipeableRow.js
|
||||
</span><span class="token function">_isSwipingExcessivelyRightFromClosedPosition<span class="token punctuation">(</span></span>gestureState<span class="token punctuation">:</span> Object<span class="token punctuation">)</span><span class="token punctuation">:</span> boolean <span class="token punctuation">{</span>
|
||||
<span class="token comment" spellcheck="true"> // ...
|
||||
</span> const gestureStateDx <span class="token operator">=</span> IS_RTL <span class="token operator">?</span> <span class="token operator">-</span>gestureState<span class="token punctuation">.</span>dx <span class="token punctuation">:</span> gestureState<span class="token punctuation">.</span>dx<span class="token punctuation">;</span>
|
||||
@@ -48,7 +46,7 @@
|
||||
<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">_isSwipingRightFromClosed<span class="token punctuation">(</span></span>gestureState<span class="token punctuation">)</span> &&
|
||||
gestureStateDx <span class="token operator">></span> RIGHT_SWIPE_THRESHOLD
|
||||
<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
||||
<span class="token punctuation">}</span><span class="token punctuation">,</span></div><h6><a class="anchor" name="animation-example"></a>Animation Example <a class="hash-link" href="#animation-example">#</a></h6><div class="prism language-javascript"><span class="token comment" spellcheck="true">// SwipeableRow.js
|
||||
<span class="token punctuation">}</span><span class="token punctuation">,</span></div><h5><a class="anchor" name="animation-example"></a>Animation Example <a class="hash-link" href="#animation-example">#</a></h5><div class="prism language-javascript"><span class="token comment" spellcheck="true">// SwipeableRow.js
|
||||
</span><span class="token function">_animateBounceBack<span class="token punctuation">(</span></span>duration<span class="token punctuation">:</span> number<span class="token punctuation">)</span><span class="token punctuation">:</span> void <span class="token punctuation">{</span>
|
||||
<span class="token comment" spellcheck="true"> // ...
|
||||
</span> const swipeBounceBackDistance <span class="token operator">=</span> IS_RTL <span class="token operator">?</span>
|
||||
@@ -86,7 +84,7 @@ _onDirectionChange <span class="token operator">=</span> <span class="token punc
|
||||
<span class="token string">'Check them out to see what they look like in RTL layout.'</span>
|
||||
<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
||||
<span class="token punctuation">}</span><span class="token punctuation">;</span></div><p>When working on a new feature, you can easily toggle this button and reload the app to see RTL layout. The benefit is you won't need to change the language setting to test, however some text alignment won't change, as explained in the next section. Therefore, it's always a good idea to test your app in the RTL language before launching.</p><h2><a class="anchor" name="limitations-and-future-plan"></a>Limitations and Future Plan <a class="hash-link" href="#limitations-and-future-plan">#</a></h2><p>The RTL support should cover most of the UX in your app; however, there are some limitations for now:</p><ul><li>Text alignment behaviors differ in iOS and Android<ul><li>In iOS, the default text alignment depends on the active language bundle, they are consistently on one side. In Android, the default text alignment depends on the language of the text content, i.e. English will be left-aligned and Arabic will be right-aligned.</li><li>In theory, this should be made consistent across platform, but some people may prefer one behavior to another when using an app. More user experience research may be needed to find out the best practice for text alignment.</li></ul></li></ul><ul><li><p>There is no "true" left/right</p><p> As discussed before, we map the <code>left</code>/<code>right</code> styles from the JS side to <code>start</code>/<code>end</code>, all <code>left</code> in code for RTL layout becomes "right" on screen, and <code>right</code> in code becomes "left" on screen. This is convenient because you don't need to change your product code too much, but it means there is no way to specify "true left" or "true right" in the code. In the future, allowing a component to control its direction regardless of the language may be necessary.</p></li><li><p>Make RTL support for gestures and animations more developer friendly</p><p> Currently, there is still some programming effort required to make gestures and animations RTL compatible.
|
||||
In the future, it would be ideal to find a way to make gestures and animations RTL support more developer friendly.</p></li></ul><h2><a class="anchor" name="try-it-out"></a>Try it Out! <a class="hash-link" href="#try-it-out">#</a></h2><p>Check out the <code>RTLExample</code> in the <code>UIExplorer</code> to understand more about RTL support, and let us know how it works for you!</p><p>Finally, thank you for reading! We hope that the RTL support for React Native helps you grow your apps for international audience!</p></div></div></div></section><footer class="wrap"><div class="center">© 2016 Facebook Inc.</div></footer></div><div id="fb-root"></div><script type="text/javascript" src="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.js"></script><script>
|
||||
In the future, it would be ideal to find a way to make gestures and animations RTL support more developer friendly.</p></li></ul><h2><a class="anchor" name="try-it-out"></a>Try it Out! <a class="hash-link" href="#try-it-out">#</a></h2><p>Check out the <a href="https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/js/RTLExample.js" target="_blank"><code>RTLExample</code></a> in the <code>UIExplorer</code> to understand more about RTL support, and let us know how it works for you!</p><p>Finally, thank you for reading! We hope that the RTL support for React Native helps you grow your apps for international audience!</p></div></div></div></section><footer class="wrap"><div class="center">© 2016 Facebook Inc.</div></footer></div><div id="fb-root"></div><script type="text/javascript" src="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.js"></script><script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
|
||||
+11
-13
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user