Welcome to Knowledge Base!

KB at your finger tips

This is one stop global knowledge base where you can learn about all the products, solutions and support features.

Categories
All

Mobile-React Native

Right-to-Left Layout Support For React Native Apps · React Native

Right-to-Left Layout Support For React Native Apps

· 7 min read

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 support RTL for them is necessary.

We're glad to announce that React Native has been improved to support RTL layouts. This is now available in the react-native master branch today, and will be available in the next RC: v0.33.0-rc .

This involved changing css-layout, the core layout engine used by RN, and RN core implementation, as well as specific OSS JS components to support RTL.

To battle test the RTL support in production, the latest version of the Facebook Ads Manager app (the first cross-platform 100% RN app) is now available in Arabic and Hebrew with RTL layouts for both iOS and Android. Here is how it looks like in those RTL languages:

Overview Changes in RN for RTL support​

css-layout already has a concept of start and end for the layout. In the Left-to-Right (LTR) layout, start means left , and end means right . But in RTL, start means right , and end means left . This means we can make RN depend on the start and end calculation to compute the correct layout, which includes position , padding , and margin .

In addition, css-layout 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.

The diagram below describes the changes at high level:

These include:

  • css-layout RTL support for absolute positioning
  • mapping left and right to start and end in RN core implementation for shadow nodes
  • and exposing a bridged utility module to help control the RTL layout

With this update, when you allow RTL layout for your app:

  • every component layout will flip horizontally
  • some gestures and animations will automatically have RTL layout, if you are using RTL-ready OSS components
  • minimal additional effort may be needed to make your app fully RTL-ready

Making an App RTL-ready​

  1. To support RTL, you should first add the RTL language bundles to your app.

    • See the general guides from iOS and Android.
  2. Allow RTL layout for your app by calling the allowRTL() function at the beginning of native code. We provided this utility to only apply to an RTL layout when your app is ready. Here is an example:

    iOS:

    // in AppDelegate.m
    [[RCTI18nUtil sharedInstance] allowRTL:YES];

    Android:

    // in MainActivity.java
    I18nUtil sharedI18nUtilInstance = I18nUtil.getInstance();
    sharedI18nUtilInstance.allowRTL(context, true);
  3. For Android, you need add android:supportsRtl="true" to the <application> element in AndroidManifest.xml file.

Now, when you recompile your app and change the device language to an RTL language (e.g. Arabic or Hebrew), your app layout should change to RTL automatically.

Writing RTL-ready Components​

In general, most components are already RTL-ready, for example:

  • Left-to-Right Layout
  • Right-to-Left Layout

However, there are several cases to be aware of, for which you will need the I18nManager . In I18nManager , there is a constant isRTL to tell if layout of app is RTL or not, so that you can make the necessary changes according to the layout.

Icons with Directional Meaning​

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
  • Right-to-Left Layout

Here are two ways to flip the icon according to the direction:

  • Adding a transform style to the image component:

    <Image
    source={...}
    style={{transform: [{scaleX: I18nManager.isRTL ? -1 : 1}]}}
    />
  • Or, changing the image source according to the direction:

    let imageSource = require('./back.png');
    if (I18nManager.isRTL) {
    imageSource = require('./forward.png');
    }
    return <Image source={imageSource} />;

Gestures and Animations​

In Android and iOS 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 SwipeableRow and NavigationExperimental . However, other components with gestures will need to support RTL manually.

A good example to illustrate gesture RTL support is SwipeableRow .

Gestures Example​
// SwipeableRow.js
_isSwipingExcessivelyRightFromClosedPosition(gestureState: Object): boolean {
// ...
const gestureStateDx = IS_RTL ? -gestureState.dx : gestureState.dx;
return (
this._isSwipingRightFromClosed(gestureState) &&
gestureStateDx > RIGHT_SWIPE_THRESHOLD
);
},
Animation Example​
// 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,
);
},

Maintaining Your RTL-ready App​

Even after the initial RTL-compatible app release, you will likely need to iterate on new features. To improve development efficiency, I18nManager provides the forceRTL() function for faster RTL testing without changing the test device language. You might want to provide a simple switch for this in your app. Here's an example from the RTL example in the RNTester:

<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.',
);
};

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.

Limitations and Future Plan​

The RTL support should cover most of the UX in your app; however, there are some limitations for now:

  • Text alignment behaviors differ in Android and iOS
    • 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.
    • 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.
  • There is no "true" left/right

    As discussed before, we map the left / right styles from the JS side to start / end , all left in code for RTL layout becomes "right" on screen, and right 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.

  • Make RTL support for gestures and animations more developer friendly

    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.

Try it Out!​

Check out the RTLExample in the RNTester to understand more about RTL support, and let us know how it works for you!

Finally, thank you for reading! We hope that the RTL support for React Native helps you grow your apps for international audience!

Tags:
  • engineering

Expo Talks: Adam on Unraveling Navigation · React Native

Expo Talks: Adam on Unraveling Navigation

· One min read

Adam Miskiewicz from Expo talks about mobile navigation and the ex-navigation React Native library at Expo's office hours last week.

Tags:
  • videos
Read article

0.36: Headless JS, the Keyboard API, & more · React Native

0.36: Headless JS, the Keyboard API, & more

· 3 min read

Today we are releasing React Native 0.36. Read on to learn more about what's new.

Headless JS​

Headless JS is a way to run tasks in JavaScript while your app is in the background. It can be used, for example, to sync fresh data, handle push notifications, or play music. It is only available on Android, for now.

To get started, define your async task in a dedicated file (e.g. SomeTaskName.js ):

module.exports = async taskData => {
// Perform your task here.
};

Next, register your task in on AppRegistry :

AppRegistry.registerHeadlessTask('SomeTaskName', () =>
require('SomeTaskName'),
);

Using Headless JS does require some native Java code to be written in order to allow you to start up the service when needed. Take a look at our new Headless JS docs to learn more!

The Keyboard API​

Working with the on-screen keyboard is now easier with Keyboard . You can now listen for native keyboard events and react to them. For example, to dismiss the active keyboard, simply call Keyboard.dismiss() :

import {Keyboard} from 'react-native';

// Hide that keyboard!
Keyboard.dismiss();

Animated Division​

Combining two animated values via addition, multiplication, and modulo are already supported by React Native. With version 0.36, combining two animated values via division is now possible. There are some cases where an animated value needs to invert another animated value for calculation. An example is inverting a scale (2x --> 0.5x):

const a = Animated.Value(1);
const b = Animated.divide(1, a);

Animated.spring(a, {
toValue: 2,
}).start();

b will then follow a 's spring animation and produce the value of 1 / a .

The basic usage is like this:

<Animated.View style={{transform: [{scale: a}]}}>
<Animated.Image style={{transform: [{scale: b}]}} />
<Animated.View>

In this example, the inner image won't get stretched at all because the parent's scaling gets cancelled out. If you'd like to learn more, check out the Animations guide.

Dark Status Bars​

A new barStyle value has been added to StatusBar : dark-content . With this addition, you can now use barStyle on both Android and iOS. The behavior will now be the following:

  • default : Use the platform default (light on iOS, dark on Android).
  • light-content : Use a light status bar with black text and icons.
  • dark-content : Use a dark status bar with white text and icons.

...and more​

The above is just a sample of what has changed in 0.36. Check out the release notes on GitHub to see the full list of new features, bug fixes, and breaking changes.

You can upgrade to 0.36 by running the following commands in a terminal:

$ npm install --save [email protected]
$ react-native upgrade
Tags:
  • announcement
Read article

Introducing Button, Faster Installs with Yarn, and a Public Roadmap · React Native

Introducing Button, Faster Installs with Yarn, and a Public Roadmap

· 3 min read

We have heard from many people that there is so much work happening with React Native, it can be tough to keep track of what's going on. To help communicate what work is in progress, we are now publishing a roadmap for React Native. At a high level, this work can be broken down into three priorities:

  • Core Libraries . Adding more functionality to the most useful components and APIs.
  • Stability . Improve the underlying infrastructure to reduce bugs and improve code quality.
  • Developer Experience . Help React Native developers move faster

If you have suggestions for features that you think would be valuable on the roadmap, check out Canny, where you can suggest new features and discuss existing proposals.

What's new in React Native​

Version 0.37 of React Native, released today, introduces a new core component to make it really easy to add a touchable Button to any app. We're also introducing support for the new Yarn package manager, which should speed up the whole process of updating your app's dependencies.

Introducing Button​

Today we're introducing a basic <Button /> component that looks great on every platform. This addresses one of the most common pieces of feedback we get: React Native is one of the only mobile development toolkits without a button ready to use out of the box.

Simple Button on Android, iOS

<Button
onPress={onPressMe}
title="Press Me"
accessibilityLabel="Learn more about this Simple Button"
/>

Experienced React Native developers know how to make a button: use TouchableOpacity for the default look on iOS, TouchableNativeFeedback for the ripple effect on Android, then apply a few styles. Custom buttons aren't particularly hard to build or install, but we aim to make React Native radically easy to learn. With the addition of a basic button into core, newcomers will be able to develop something awesome in their first day, rather than spending that time formatting a Button and learning about Touchable nuances.

Button is meant to work great and look native on every platform, so it won't support all the bells and whistles that custom buttons do. It is a great starting point, but is not meant to replace all your existing buttons. To learn more, check out the new Button documentation, complete with a runnable example!

Speed up react-native init using Yarn​

You can now use Yarn, the new package manager for JavaScript, to speed up react-native init significantly. To see the speedup please install yarn and upgrade your react-native-cli to 1.2.0:

$ npm install -g react-native-cli

You should now see “Using yarn” when setting up new apps:

Using yarn

In simple local testing react-native init finished in about 1 minute on a good network (vs around 3 minutes when using npm 3.10.8). Installing yarn is optional but highly recommended.

Thank you!​

We'd like to thank everyone who contributed to this release. The full release notes are now available on GitHub. With over two dozen bug fixes and new features, React Native just keeps getting better thanks to you.

Tags:
  • announcement
Read article

Easier Upgrades Thanks to Git · React Native

Easier Upgrades Thanks to Git

· 4 min read

Upgrading to new versions of React Native has been difficult. You might have seen something like this before:

None of those options is ideal. By overwriting the file we lose our local changes. By not overwriting we don't get the latest updates.

Today I am proud to introduce a new tool that helps solve this problem. The tool is called react-native-git-upgrade and uses Git behind the scenes to resolve conflicts automatically whenever possible.

Usage​

Requirement : Git has to be available in the PATH . Your project doesn't have to be managed by Git.

Install react-native-git-upgrade globally:

$ npm install -g react-native-git-upgrade

or, using Yarn:

$ yarn global add react-native-git-upgrade

Then, run it inside your project directory:

$ cd MyProject
$ react-native-git-upgrade 0.38.0

Note: Do not run 'npm install' to install a new version of react-native . The tool needs to be able to compare the old and new project template to work correctly. Simply run it inside your app folder as shown above, while still on the old version.

Example output:

You can also run react-native-git-upgrade with no arguments to upgrade to the latest version of React Native.

We try to preserve your changes in Android and iOS build files, so you don't need to run react-native link after an upgrade.

We have designed the implementation to be as little intrusive as possible. It is entirely based on a local Git repository created on-the-fly in a temporary directory. It won't interfere with your project repository (no matter what VCS you use: Git, SVN, Mercurial, ... or none). Your sources are restored in case of unexpected errors.

How does it work?​

The key step is generating a Git patch. The patch contains all the changes made in the React Native templates between the version your app is using and the new version.

To obtain this patch, we need to generate an app from the templates embedded in the react-native package inside your node_modules directory (these are the same templates the react-native init commands uses). Then, after the native apps have been generated from the templates in both the current version and the new version, Git is able to produce a patch that is adapted to your project (i.e. containing your app name):

[...]

diff --git a/ios/MyAwesomeApp/Info.plist b/ios/MyAwesomeApp/Info.plist
index e98ebb0..2fb6a11 100644
--- a/ios/MyAwesomeApp/Info.plist
+++ b/ios/MyAwesomeApp/Info.plist
@@ -45,7 +45,7 @@
<dict>
<key>localhost</key>
<dict>
- <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
+ <key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
[...]

All we need now is to apply this patch to your source files. While the old react-native upgrade process would have prompted you for any small difference, Git is able to merge most of the changes automatically using its 3-way merge algorithm and eventually leave us with familiar conflict delimiters:

        13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
<<<<<<< ours
CODE_SIGN_IDENTITY = "iPhone Developer";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/HockeySDK.embeddedframework",
"$(PROJECT_DIR)/HockeySDK-iOS/HockeySDK.embeddedframework",
);
=======
CURRENT_PROJECT_VERSION = 1;
>>>>>>> theirs
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../node_modules/react-native/React/**",
"$(SRCROOT)/../node_modules/react-native-code-push/ios/CodePush/**",
);

These conflicts are generally easy to reason about. The delimiter ours stands for "your team" whereas theirs could be seen as "the React Native team".

Why introduce a new global package?​

React Native comes with a global CLI (the react-native-cli package) which delegates commands to the local CLI embedded in the node_modules/react-native/local-cli directory.

As we mentioned above, the process has to be started from your current React Native version. If we had embedded the implementation in the local-cli, you wouldn't be able to enjoy this feature when using old versions of React Native. For example, you wouldn't be able to upgrade from 0.29.2 to 0.38.0 if this new upgrade code was only released in 0.38.0.

Upgrading based on Git is a big improvement in developer experience and it is important to make it available to everyone. By using a separate package react-native-git-upgrade installed globally you can use this new code today no matter what version of React Native your project is using.

One more reason is the recent Yeoman wipeout by Martin Konicek. We didn't want to get these Yeoman dependencies back into the react-native package to be able to evaluate the old template in order to create the patch.

Try it out and provide feedback​

As a conclusion, I would say, enjoy the feature and feel free to suggest improvements, report issues and especially send pull requests. Each environment is a bit different and each React Native project is different, and we need your feedback to make this work well for everyone.

Thank you!​

I would like to thank the awesome companies Zenika and M6 Web without whom none of this would have been possible!

Tags:
  • announcement
Read article

Introducing Create React Native App · React Native

Introducing Create React Native App

· 2 min read

Today we’re announcing Create React Native App: a new tool that makes it significantly easier to get started with a React Native project! It’s heavily inspired by the design of Create React App and is the product of a collaboration between Facebook and Expo (formerly Exponent).

Many developers struggle with installing and configuring React Native’s current native build dependencies, especially for Android. With Create React Native App, there’s no need to use Xcode or Android Studio, and you can develop for your iOS device using Linux or Windows. This is accomplished using the Expo app, which loads and runs CRNA projects written in pure JavaScript without compiling any native code.

Try creating a new project (replace with suitable yarn commands if you have it installed):

$ npm i -g create-react-native-app
$ create-react-native-app my-project
$ cd my-project
$ npm start

This will start the React Native packager and print a QR code. Open it in the Expo app to load your JavaScript. Calls to console.log are forwarded to your terminal. You can make use of any standard React Native APIs as well as the Expo SDK.

What about native code?​

Many React Native projects have Java or Objective-C/Swift dependencies that need to be compiled. The Expo app does include APIs for camera, video, contacts, and more, and bundles popular libraries like Airbnb’s react-native-maps, or Facebook authentication. However if you need a native code dependency that Expo doesn’t bundle then you’ll probably need to have your own build configuration for it. Just like Create React App, “ejecting” is supported by CRNA.

You can run npm run eject to get a project very similar to what react-native init would generate. At that point you’ll need Xcode and/or Android Studio just as you would if you started with react-native init , adding libraries with react-native link will work, and you’ll have full control over the native code compilation process.

Questions? Feedback?​

Create React Native App is now stable enough for general use, which means we’re very eager to hear about your experience using it! You can find me on Twitter or open an issue on the GitHub repository. Pull requests are very welcome!

Tags:
  • engineering
Read article