Blog

React Native – How To Handle Deep Linking in React Native ?

Hello Readers, CoolMonkTechie heartily welcomes you in this article (How To Handle Deep Linking in React Native ?).

In this article, We will learn how to handle deep linking in react native. Mobile apps have a unique vulnerability that is non-existent in the web: Deep Linking. Deep Linking is a technique in which a given URL or resource is used to open a specific page or screen on mobile. So, instead of just launching the app on mobile, a deep link can lead a user to a specific page within the app, providing a better experience. This specific page or screen may reside under a series of hierarchical pages, hence the term “deep” in deep linking.

Deep linking is a way of sending data directly to a native application from an outside source. A deep link looks like app:// where app is our app scheme and anything following the // could be used internally to handle the request. As a user, we probably have experienced deep linking when opening a link to a product in a browser. If we have the app of that shop installed, it may use a deep link to open the app on that product’s page.

For example, if we were building an e-commerce app, we could use app://products/1 to deep link to our app and open the product detail page for a product with id 1. We can think of these kind of like URLs on the web.

Deep linking consists of using a uniform resource identifier (URI) that links to a specific location within a mobile app rather than simply launching the app. Deferred deep linking allows users to deep link to content even if the app is not already installed.

In this article, we will discuss a React Native app that opens a specific page based on the URI provided from an external source.

A famous quote about learning is :

” The beautiful thing about learning is nobody can take it away from you. “

So Let’s begin.


Why Deep Linking?

Deep Link has many use cases where it can come very handy. Think of marketing strategies, referral links, sharing a certain product, etc. The greatest benefit of mobile deep linking is the ability for marketers and app developers to bring users directly into the specific location within their app with a dedicated link. Just as deep links made the web more usable, mobile deep links do the same for mobile apps.


Example

Let’s try to mimic a React Native demo app that opens a specific page based on the URI provided from an external source. To handle deep links, we are going to use an optimum solution provided by the react-navigation library.


Configure react-navigation in a React Native App

To start, we create a new React Native project by running the following command:

react-native init rnDeepLinkingDemo

cd rnDeepLinkingDemo

To be able to support deep linking via the navigation, we add the required npm dependencies. Once the project directory has been generated from the above command, navigate inside the project folder from our terminal and install the following dependencies.

npm install react-navigation --save

npm install react-native-gesture-handler react-native-safe-area-context @react-native-community/masked-view react-native-screens react-native-reanimated --save

npm install react-navigation-stack --save

The next step is to link all the libraries we just installed. From React Native 0.60 and higher, linking is automatic. So we don’t need to run react-native link.

On iOS devices, we just have to run the following set of commands.

cd ios
pod install
cd ..

For Android devices, we add the following lines to the android/app/build.gradle file under the dependencies section:

implementation 'androidx.appcompat:appcompat:1.1.0-rc01'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-alpha02'

Then, open the android/app/src/main/java/com/rndeeplinkdemo/MainActivity.java file and add the following snippet:

package com.rndeeplinkingdemo;

import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;

public class MainActivity extends ReactActivity {

  /**
   * Returns the name of the main component registered from JavaScript. This is used to schedule
   * rendering of the component.
   */
  @Override
  protected String getMainComponentName() {
    return "RNDeepLinkingDemo";
  }

  protected ReactActivityDelegate createReactActivityDelegate() {
    return new ReactActivityDelegate(this, getMainComponentName()) {
        @Override
        protected ReactRootView createRootView() {
            return new RNGestureHandlerEnabledRootView(MainActivity.this);
        }
    };
  }

}


Create a Home & Details Screen

We are going to create all the screens for this example inside the directory src/screens. To start with the home screen, create a new file Home.js inside the aforementioned path.

This screen is going to render a list of users from an array of mock data from a placeholder API using a FlatList component. Each user is going to be wrapped inside a TouchableOpacity. The reason being, when an end-user presses a username from the list, this is going to contain the logic for navigating from the Home screen to the Details screen (which we will add later).

import React, {useState, useEffect} from 'react';
import {View, Text, FlatList, TouchableOpacity} from 'react-native';

function Home({navigation}) {
  const [data, setData] = useState([]);

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/users')
      .then((res) => res.json())
      .then((res) => {
        setData(res);
      })
      .catch((error) => {
        console.log(error);
      });
  }, []);

  const Separator = () => (
    <View
      style={{
        borderBottomColor: '#d3d3d3',
        borderBottomWidth: 1,
        marginTop: 10,
        marginBottom: 10,
      }}
    />
  );
  return (
    <View style={{flex: 1}}>
      <View style={{paddingHorizontal: 20, paddingVertical: 20}}>
        <FlatList
          data={data}
          keyExtractor={(item) => item.id.toString()}
          ItemSeparatorComponent={Separator}
          renderItem={({item}) => (
            <TouchableOpacity
              onPress={() => navigation.navigate('Details', {item})}>
              <Text style={{fontSize: 24}}>{item.name}</Text>
            </TouchableOpacity>
          )}
        />
      </View>
    </View>
  );
}
export default Home;

For the details screen, for now, let us display user list details. We create a new file called Details.js. To display information for each user when visiting the Details screen, we have to pass the value of each item using navigation parameters. Next, To fetch the data from the placeholder API on initial render, let us use the useEffect hook from React. This hook is going to behave like a good old lifecycle method componentDidMount(). It also allows that if the full item object is passed or not. If not, just grab the userId and request the API. Then, define a state variable data to store the incoming user information. Also, modify the contents of return in this component screen.

import React, {useState, useEffect} from 'react';
import {View, Text} from 'react-native';

function Details({navigation}) {
  const [data, setData] = useState([]);

  useEffect(() => {
    const item = navigation.getParam('item', {});

    if (Object.keys(item).length === 0) {
      const userId = navigation.getParam('userId', 1);
      fetch(`https://jsonplaceholder.typicode.com/users/${userId}`)
        .then((res) => res.json())
        .then((res) => {
          const data = [];

          Object.keys(res).forEach((key) => {
            data.push({key, value: `${res[key]}`});
          });

          setData(data);
        });
    } else {
      const data = [];

      Object.keys(item).forEach((key) => {
        data.push({key, value: `${item[key]}`});
      });

      setData(data);
    }
  }, []);

  return (
    <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
      {data.map((data) => (
        <Text
          style={{fontSize: 20}}
          key={data.key}>{`${data.key}: ${data.value}`}</Text>
      ))}
    </View>
  );
}

export default Details;


Configure Deep Linking in React Navigation

To navigate from Home to Details screen, we need Stack Navigator from react-navigation. We create a new file called index.js inside the src/navigation directory and import the following statements.

import React from 'react'
import { createAppContainer, createSwitchNavigator } from 'react-navigation'
import { createStackNavigator } from 'react-navigation-stack'
import Home from '../screens/Home'
import Details from '../screens/Details'

Create a stack navigator with Home as the initial screen. To enable deep linking, the current app requires an identifier to recognize the URI path from the external source to the screen of the app. The library react-navigation provides a path attribute for this. It tells the router relative path to match against the URL. We configure both the routes as follows:

const MainApp = createStackNavigator({
  Home: {
    screen: Home,
    navigationOptions: {
      headerTitle: 'Home',
    },
    path: 'home',
  },
  Details: {
    screen: Details,
    navigationOptions: {
      headerTitle: 'Details',
    },
    path: 'details/:userId',
  },
});

In the above snippet, the dynamic variable specified by :userId is passed to details/. This is going to allow the app to accept a dynamic value such as details/1234.

Next, we add the configuration to the navigation to extract the path from the incoming URL from the external resource. This is done by uriPrefix. Add the following code snippet at the end of the file:

export default () => {
  const prefix = 'myapp://';
  return <AppContainer uriPrefix={prefix} />;
};

The full code of index.js file is as below :

import React from 'react';
import {createAppContainer} from 'react-navigation';
import {createStackNavigator} from 'react-navigation-stack';
import Home from '../screens/Home';
import Details from '../screens/Details';

const MainApp = createStackNavigator({
  Home: {
    screen: Home,
    navigationOptions: {
      headerTitle: 'Home',
    },
    path: 'home',
  },
  Details: {
    screen: Details,
    navigationOptions: {
      headerTitle: 'Details',
    },
    path: 'details/:userId',
  },
});

const AppContainer = createAppContainer(MainApp);

export default () => {
  const prefix = 'myapp://';
  return <AppContainer uriPrefix={prefix} />;
};

Import this navigation module inside the App.js file for it to work:

import React from 'react';
import AppContainer from './src/navigation';

const App = () => {
  return <AppContainer />;
};

export default App;


Configure URI Scheme For Native iOS Apps

To make this work, we have to configure the native iOS and Android app to open URLs based on the prefix myapp://.

For iOS devices, open the ios/rnDeepLinkDemo/AppDelegate.m file and add the following.

// Add the header at the top of the file:
#import <React/RCTLinkingManager.h>
// Add this above the `@end`:
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url
 options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
 return [RCTLinkingManager application:app openURL:url options:options];
}

Open ios/rnDeepLinkingDemo.xcodeproj in the Xcode app and select the app from the left navigation bar.

Open the Info tab.

Next, go to the URL Types.

Click the + button and in identifier as well as URL schemes add myapp.

Rebuild the React Native binaries by running react-native run-ios.

For Android users, we have to configure the external linking as well. Open /android/app/src/main/AndroidManifest.xml and set the value of launchMode to singleTask. Also, add a new intent-filter:

<activity
 android:name=".MainActivity"
 <!--set the below value-->
 android:launchMode="singleTask">
 <intent-filter>
 <action android:name="android.intent.action.MAIN" />
 <category android:name="android.intent.category.LAUNCHER" />
 </intent-filter>
 <!--Add the following-->

 <intent-filter>
 <action android:name="android.intent.action.VIEW" />
 <category android:name="android.intent.category.DEFAULT" />
 <category android:name="android.intent.category.BROWSABLE" />
 <data android:scheme="myapp" />
 </intent-filter>
</activity>

Let’s understand the intent-filter a little better.

An intent filter is an expression in an app’s manifest file that specifies the type of intents that the component would like to receive.

Get a closer look on <data> tag inside <intent-filter>. There are two properties that we have to care about. Consider scheme as a type of incoming link and host as the URL.

Our Deep Link will look something like this: myapp://home .


Testing The App

Before we run the app on our platform of choice, make sure to re-build it using the specific command for the mobile OS as below:

# ios
react-native run-ios

# android
react-native run-android

The Example app output is going to be like below.

To test deep link in iOS, we open a web browser in our iOS simulator device and run the URL myapp://home. It is going to ask us to whether open the external URI in the app . Next, try entering the URL myapp://details/1 and see what happens.

To test deep link in Android, we make sure our android app is in background and run this command:

adb shell am start -W -a android.intent.action.VIEW -d myapp://home com.rndeeplinkingdemo

adb shell am start -W -a android.intent.action.VIEW -d myapp://details/1 com.rndeeplinkingdemo

If our package has a different name then edit command as follows:

$ adb shell am start -W -a android.intent.action.VIEW -d <URI> <PACKAGE>

If our App opened successfully then our Deep Linking is working as expected.

That’s all about in this article.


Conclusion

In this article, We understood how to handle Deep Linking in React Native. We also discussed about a complete demo of a React Native app that handles deep linking using react-navigation. Deep linking can bring significant improvements to the user experience of our mobile apps and enable search engines to provide context-sensitive searches and results.

Thanks for reading ! I hope you enjoyed and learned about the Deep Linking Concepts in React Native. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolmonkTechie as below link :

You can also follow official website and tutorials of React Native as below links :

React Native Official Website

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING!!???

A Short Note – How Authentication Works In React Native ?

Hello Readers, CoolMonkTechie heartily welcomes you in A Short Note Series (How Authentication Works In React Native ?) .

In this note series, we will learn how Authentication Works In React Native. Mostly Authentication is done by the OAuth2 Authentication Protocol in React Native application. This protocol is incredibly popular nowadays, prided as the most complete and secure protocol around. The OpenID Connect protocol is also based on this protocol.

So Let’s begin.

OAuth2 and Redirects

The OAuth2 authentication protocol is incredibly popular and the most complete and secure protocol around. In OAuth2, the user asks to the authenticate via a third party. On successful completion, this third party redirects back to the requesting application with a verification code which can be exchanged for a JWT — a JSON Web Token. JWT is an open standard for securely transmitting information between parties on the web.

PKCE (Proof of Key Code Exchange)

On the web, this redirect step is secure, because it guarantees URLs to be unique on the web. This is not true for apps because, as mentioned earlier, there is no centralized method of registering URL schemes! In order to address this security concern, an additional check must be added in the form of PKCE.

PKCE, pronounced “Pixy” stands for Proof of Key Code Exchange, and is an extension to the OAuth 2 spec. This involves adding a layer of security, which verifies that the authentication and token exchange requests come from the same client. PKCE uses the SHA 256 Cryptographic Hash Algorithm. SHA 256 creates a unique “signature” for a text or file of any size, but it is:

  • Always the same length regardless of the input file.
  • Guaranteed to be always produce the same result for the same input.
  • One way (that is, we can’t reverse engineer it to reveal the original input).

Now we have two values:

  • code_verifier – a large random string generated by the client.
  • code_challenge – the SHA 256 of the code_verifier.

During the initial /authorize request, the client also sends the code_challenge for the code_verifier , it keeps in memory. After the authorize request has returned correctly, the client also sends the code_verifier that was used to generate the code_challenge. The IDP will then calculate the code_challenge, see if it matches what was set on the very first /authorize request, and only send the access token if the values match.

This guarantees that only the application that triggered the initial authorization flow would be able to successfully exchange the verification code for a JWT. So even if a malicious application gets access to the verification code, it will be useless on its own.

OAuth Library

A library to consider for native OAuth is react-native-app-auth. React-native-app-auth is an SDK for communicating with OAuth2 providers. It wraps the native AppAuth-iOS and AppAuth-Android libraries and can support PKCE. React-native-app-auth can support PKCE only if our Identity Provider supports it.

Conclusion

In this note series, we understood how Authentication works in React Native. We discussed the work flow of OAuth2 Authentication Protocol with PKCE in react native.

Thanks for reading ! I hope you enjoyed and learned about OAuth2 Authentication Protocol concept in React Native. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe to the blog and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolmonkTechie as below link :

You can also follow official website and tutorials of React Native as below links :

If you have any comments, questions, or think I missed something, leave them below in the comment box.

Thanks again Reading. HAPPY READING !!???

React Native – How To Manage The Lifecycle of Gestures In React Native ?

Hello Readers, CoolMonkTechie heartily welcomes you in this article (How To Manage The Lifecycle of Gestures In React Native ?).

In this article, We will learn how to manage the lifecycle of gestures in react native. The gesture responder system manages the lifecycle of gestures in react native application. A touch can go through several phases as the app determines what the user’s intention is. For example, the app needs to determine if the touch is scrolling, sliding on a widget, or tapping. This can even change during the duration of a touch. There can also be multiple simultaneous touches.

The touch responder system is needed to allow components to negotiate these touch interactions without any additional knowledge about their parent or child components.

A famous quote about learning is :

” Change is the end result of all true learning. “

So Let’s begin.


Best Practices

To make our app feel great, every action should have the following attributes:

  • Feedback/highlighting – show the user what is handling their touch, and what will happen when they release the gesture
  • Cancel-ability – when making an action, the user should be able to abort it mid-touch by dragging their finger away

These features make users more comfortable while using an app, because it allows people to experiment and interact without fear of making mistakes.


TouchableHighlight and Touchable

The responder system can be complicated to use. So we have provided an abstract Touchable implementation for things that should be “tappable“. This uses the responder system and allows us to configure tap interactions declaratively. Use TouchableHighlight anywhere where we would use a button or link on web.


Gesture Responder System Lifecycle

A view can become the touch responder by implementing the correct negotiation methods. There are two methods to ask the view if it wants to become responder:

  • View.props.onStartShouldSetResponder: (evt) => true, – Does this view want to become responder on the start of a touch?
  • View.props.onMoveShouldSetResponder: (evt) => true, – Called for every touch move on the View when it is not the responder: does this view want to “claim” touch responsiveness?

If the View returns true and attempts to become the responder, one of the following will happen:

  • View.props.onResponderGrant: (evt) => {} – The View is now responding for touch events. This is the time to highlight and show the user what is happening.
  • View.props.onResponderReject: (evt) => {} – Something else is the responder right now and will not release it.

If the view is responding, the following handlers can be called:

  • View.props.onResponderMove: (evt) => {} – The user is moving their finger.
  • View.props.onResponderRelease: (evt) => {} – Fired at the end of the touch, ie “touchUp”.
  • View.props.onResponderTerminationRequest: (evt) => true – Something else wants to become responder. Should this view release the responder? Returning true allows release.
  • View.props.onResponderTerminate: (evt) => {} – The responder has been taken from the View. Might be taken by other views after a call to onResponderTerminationRequest, or might be taken by the OS without asking (happens with control center/ notification center on iOS).

evt is a synthetic touch event with the following nativeEvent form:

  • changedTouches – Array of all touch events that have changed since the last event
  • identifier – The ID of the touch
  • locationX – The X position of the touch, relative to the element
  • locationY – The Y position of the touch, relative to the element
  • pageX – The X position of the touch, relative to the root element
  • pageY – The Y position of the touch, relative to the root element
  • target – The node id of the element receiving the touch event
  • timestamp – A time identifier for the touch, useful for velocity calculation
  • touches – Array of all current touches on the screen


Capture ShouldSet Handlers

onStartShouldSetResponder and onMoveShouldSetResponder are called with a bubbling pattern, where the deepest node is called first. That means that the deepest component will become responder when multiple Views return true for ShouldSetResponder handlers. This is desirable in most cases, because it makes sure all controls and buttons are usable.

However, sometimes a parent will want to make sure that it becomes responder. This can be handled by using the capture phase. Before the responder system bubbles up from the deepest component, it will do a capture phase, firing on ShouldSetResponderCapture. So if a parent View wants to prevent the child from becoming responder on a touch start, it should have a onStartShouldSetResponderCapture handler which returns true.

  • View.props.onStartShouldSetResponderCapture: (evt) => true,
  • View.props.onMoveShouldSetResponderCapture: (evt) => true,


Pan Responder

PanResponder reconciles several touches into a single gesture. It makes single-touch gestures resilient to extra touches, and can be used to recognize basic multi-touch gestures.

By default, PanResponder holds an InteractionManager handle to block long-running JS events from interrupting active gestures.

It provides a predictable wrapper of the responder handlers provided by the gesture responder system. For each handler, it provides a new gestureState object alongside the native event object:

onPanResponderMove: (event, gestureState) => {}

A native event is a synthetic touch event with form of PressEvent.

gestureState object has the following:

  • stateID – ID of the gestureState- persisted as long as there at least one touch on screen
  • moveX – the latest screen coordinates of the recently-moved touch
  • moveY – the latest screen coordinates of the recently-moved touch
  • x0 – the screen coordinates of the responder grant
  • y0 – the screen coordinates of the responder grant
  • dx – accumulated distance of the gesture since the touch started
  • dy – accumulated distance of the gesture since the touch started
  • vx – current velocity of the gesture
  • vy – current velocity of the gesture
  • numberActiveTouches – Number of touches currently on screen


API

Only a single component can respond to touch events at one time – the component responding to events owns a global “interaction lock”. The PanResponder API helps us manage what component owns this lock through a set of callbacks. Each of these callbacks is also passed an event and gestureState object containing info about the touch events (e.g. position and velocity).

To create a PanResponder, we call PanResponder.create(callbacksObject). The result is a set of props that can be passed to View as props (these are the lower-level touch event handling props). We’ll typically wrap the result with useRef, since we only want to create a single PanResponder for the lifecycle of the component.

The full set of callbacks we can pass is:

  • onStartShouldSetPanResponder: (event, gestureState) => {}
  • onStartShouldSetPanResponderCapture: (event, gestureState) => {}
  • onMoveShouldSetPanResponder: (event, gestureState) => {}
  • onMoveShouldSetPanResponderCapture: (event, gestureState) => {}
  • onPanResponderReject: (event, gestureState) => {}
  • onPanResponderGrant: (event, gestureState) => {}
  • onPanResponderStart: (event, gestureState) => {}
  • onPanResponderEnd: (event, gestureState) => {}
  • onPanResponderRelease: (event, gestureState) => {}
  • onPanResponderMove: (event, gestureState) => {}
  • onPanResponderTerminate: (event, gestureState) => {}
  • onPanResponderTerminationRequest: (event, gestureState) => {}
  • onShouldBlockNativeResponder: (event, gestureState) => {}


Usage Pattern

const ExampleComponent = () => {
  const panResponder = React.useRef(
    PanResponder.create({
      // Ask to be the responder:
      onStartShouldSetPanResponder: (evt, gestureState) => true,
      onStartShouldSetPanResponderCapture: (evt, gestureState) =>
        true,
      onMoveShouldSetPanResponder: (evt, gestureState) => true,
      onMoveShouldSetPanResponderCapture: (evt, gestureState) =>
        true,

      onPanResponderGrant: (evt, gestureState) => {
        // The gesture has started. Show visual feedback so the user knows
        // what is happening!
        // gestureState.d{x,y} will be set to zero now
      },
      onPanResponderMove: (evt, gestureState) => {
        // The most recent move distance is gestureState.move{X,Y}
        // The accumulated gesture distance since becoming responder is
        // gestureState.d{x,y}
      },
      onPanResponderTerminationRequest: (evt, gestureState) =>
        true,
      onPanResponderRelease: (evt, gestureState) => {
        // The user has released all touches while this view is the
        // responder. This typically means a gesture has succeeded
      },
      onPanResponderTerminate: (evt, gestureState) => {
        // Another component has become the responder, so this gesture
        // should be cancelled
      },
      onShouldBlockNativeResponder: (evt, gestureState) => {
        // Returns whether this component should block native components from becoming the JS
        // responder. Returns true by default. Is currently only supported on android.
        return true;
      }
    })
  ).current;

  return <View {...panResponder.panHandlers} />;
};


Example

PanResponder works with Animated API to help build complex gestures in the UI. The following example contains an animated View component which can be dragged freely across the screen.

import React, { useRef } from "react";
import { Animated, View, StyleSheet, PanResponder, Text } from "react-native";

const App = () => {
  const pan = useRef(new Animated.ValueXY()).current;

  const panResponder = useRef(
    PanResponder.create({
      onMoveShouldSetPanResponder: () => true,
      onPanResponderGrant: () => {
        pan.setOffset({
          x: pan.x._value,
          y: pan.y._value
        });
      },
      onPanResponderMove: Animated.event(
        [
          null,
          { dx: pan.x, dy: pan.y }
        ]
      ),
      onPanResponderRelease: () => {
        pan.flattenOffset();
      }
    })
  ).current;

  return (
    <View style={styles.container}>
      <Text style={styles.titleText}>Drag this box!</Text>
      <Animated.View
        style={{
          transform: [{ translateX: pan.x }, { translateY: pan.y }]
        }}
        {...panResponder.panHandlers}
      >
        <View style={styles.box} />
      </Animated.View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center"
  },
  titleText: {
    fontSize: 14,
    lineHeight: 24,
    fontWeight: "bold"
  },
  box: {
    height: 150,
    width: 150,
    backgroundColor: "blue",
    borderRadius: 5
  }
});

export default App;

The output of the above example is :

That’s all about in this article.


Conclusion

In this article, We understood how to manage the lifecycle of gestures in react native. We also discussed about Best Practices and PanResponser usage in React Native platform.

Thanks for reading ! I hope you enjoyed and learned about the Gestures Concepts in React Native. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolmonkTechie as below link :

You can also follow official website and tutorials of React Native as below links :

React Native Official Website

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING!!???

React Native – How To Navigate Between Screens In React Native ?

Hello Readers, CoolMonkTechie heartily welcomes you in this article (How To Navigate Between Screens In React Native ?).

In this article, We will learn how to navigate between screens in react native. Mobile apps are rarely made up of a single screen. Managing the presentation of, and transition between, multiple screens is typically handled by what is known as a navigator. This article covers the various navigation components available in React Native. If we are getting started with navigation, we will probably want to use React Navigation. React Navigation provides a straightforward navigation solution, with the ability to present common stack navigation and tabbed navigation patterns on both Android and iOS.

If we’d like to achieve a native look and feel on both Android and iOS, or we’re integrating React Native into an app that already manages navigation natively, the following library provides native navigation on both platforms: react-native-navigation.

A famous quote about learning is :

” Study hard what interests you the most in the most undisciplined, irreverent and original manner possible. “

So Let’s begin.


Overview

The community solution to navigation is a standalone library that allows developers to set up the screens of an app with a few lines of code.

React Navigation is the most popular navigation library. It handles most of the challenges described above nicely, and is sufficiently configurable for most apps.

React Navigation provides all the different type of navigator like

  • Stack Navigator : For the simple screen switching
  • Drawer Navigator : To create Navigation Drawer/ Sidebar
  • Bottom Tab Navigator : For the bottom navigation
  • Top Tab Navigator : To create the tab navigation


Navigation Challenges

There are a few aspects of navigation which make it challenging in React Native:

  • Navigation works differently on each native platform. iOS uses view controllers, while android uses activities. These platform-specific APIs work differently technically and appear differently to the user. React Native navigation libraries try to support the look-and-feel of each platform, while still providing a single consistent JavaScript API.
  • Native navigation APIs don’t correspond with “views”. React Native components like ViewText, and Image, roughly map to an underlying native “view”, but there isn’t really an equivalent for some of the navigation APIs. There isn’t always a clear way to expose these APIs to JavaScript.
  • Navigation on mobile is stateful. On the web, navigation is typically stateless, where a url (i.e. route) takes a user to a single screen/page. On mobile, the history of the user’s navigation state is persisted in the application so that the user can go back to previous screens – a stack of screens can even include the same screen multiple times.

Due to these challenges, there isn’t a single best way to implement navigation, so it was removed from the core React Native package.


Installation and Setup

First, we need to install them in our project:

npm install @react-navigation/native @react-navigation/stack

Next, we install the required peer dependencies. We need to run different commands depending on whether our project is an Expo managed project or a bare React Native project.

  • If we have an Expo managed project, install the dependencies with expo:
expo install react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view
  • If we have a bare React Native project, install the dependencies with npm:
npm install react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view

For iOS with bare React Native project, make sure we have Cocoapods installed. Then we install the pods to complete the installation:

cd ios
pod install
cd ..

We might get warnings related to peer dependencies after installation. They are usually caused by incorrect version ranges specified in some packages. We can safely ignore most warnings as long as our app builds.

To finalize installation of react-native-gesture-handler, add the following at the top (make sure it’s at the top and there’s nothing else before it) of our entry file, such as index.js or App.js:

import 'react-native-gesture-handler';

Now, we need to wrap the whole app in NavigationContainer. Usually we’d do this in our entry file, such as index.js or App.js :

import 'react-native-gesture-handler';
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';

const App = () => {
  return (
    <NavigationContainer>
      {/* Rest of app code */}
    </NavigationContainer>
  );
};

export default App;

Now we are ready to build and run our app on the device/simulator.


Steps For Adding React Navigation To The App

In this section, we’ll walk through adding react-navigation to an app.

After install the required dependencies, we need to do 3 things:

  • Set up a <NavigationContainer> from @react-navigation/native
  • Create a navigator:
    • createStackNavigator from @react-navigation/stack
    • createBottomTabNavigator from @react-navigation/bottom-tabs
    • createDrawerNavigator from @react-navigation/drawer
  • Define the screens in our app


1. Create a navigator

We first choose one of the available navigators, e.g. stack, which will act as our root navigator. Navigators may be nested later.

import { createStackNavigator } from '@react-navigation/stack'

const Root = createStackNavigator()


2. Create screen components

Next, we create a component for each screen.

Screens are regular React components. They’ll be passed navigation-specific props when instantiated.

const Screen1 = ({ navigation, route }) => {
  return <Text>Screen1</Text>
}


3. Render it

Lastly, we render a NavigationContainer with our navigator within it.

Each Screen component defines a route in our app. If we want nested navigators, e.g. a tab navigator within a stack navigator, we can use another navigator as a screen’s component. We only need a single NavigationContainer, even if we have nested navigators.

import { NavigationContainer } from '@react-navigation/native'

// ...

const App = () => {
  return (
    <NavigationContainer>
      <Root.Navigator>
        <Root.Screen name="Screen1" component={Screen1} />
        <Root.Screen name="Screen2" component={Screen2} />
        <Root.Screen name="Screen3" component={Screen3} />
      </Root.Navigator>
    </NavigationContainer>
  )
}


Navigating and Routes

Each navigator supports different ways of navigating:

  • Stack: push
  • Tabs: navigate
  • Drawer: openDrawer

When navigating, we typically specify a screen name and optionally parameters, e.g. navigator.push("Screen2", { paramA: "Hello!" }).


Navigation

In this example, we navigate from Screen1 to Screen2 by pushing Screen2 onto the stack when a button is pressed.

const Screen1 = ({ navigation }) => {
  return (
    <Button
      onPress={() => {
        navigation.push('Screen2', { paramA: 'Hello!' })
      }}
    />
  )
}


Routes

Within a screen, we have access to the current route and it’s parameters.

const Screen2 = ({ route }) => {
  return <Text>{route.params.paramA}</Text>
}


Hooks

For components which aren’t screens (direct descendants of a navigator), we can access the navigation and route objects using hooks. Some developers prefer using these hooks instead of props, even in screen components.

import { useNavigation, useRoute } from '@react-navigation/native'

const Screen1 = () => {
  const navigation = useNavigation()
  const route = useRoute()

  // ...
}


Usage

Now we can create an app with a home screen and a profile screen:

import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';

const Stack = createStackNavigator();

const MyStack = () => {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen
          name="Home"
          component={HomeScreen}
          options={{ title: 'Welcome' }}
        />
        <Stack.Screen name="Profile" component={ProfileScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
};

In this example, there are 2 screens (Home and Profile) defined using the Stack.Screen component. Similarly, we can define as many screens as we like.

We can set options such as the screen title for each screen in the options prop of Stack.Screen.

Each screen takes a component prop that is a React component. Those components receive a prop called navigation which has various methods to link to other screens. For example, we can use navigation.navigate to go to the Profile screen:

const HomeScreen = ({ navigation }) => {
  return (
    <Button
      title="Go to Jane's profile"
      onPress={() =>
        navigation.navigate('Profile', { name: 'Jane' })
      }
    />
  );
};
const ProfileScreen = () => {
  return <Text>This is Jane's profile</Text>;
};

The views in the stack navigator use native components and the Animated library to deliver 60fps animations that are run on the native thread. Plus, the animations and gestures can be customized.

React Navigation also has packages for different kind of navigators such as tabs and drawer. We can use them to implement various patterns in our app.

That’s all about in this article.


Conclusion

In this article, We understood how to navigate between screens in react native. We also discussed about navigation challenges, dependencies and navigation usage in React Native platform.

Thanks for reading ! I hope you enjoyed and learned about the Navigation Concepts in React Native. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolmonkTechie as below link :

You can also follow official website and tutorials of React Native as below links :

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING!!???

A Short Note – In Which Order Custom Code Executes At Launch Time In iOS ?

Hello Readers, CoolMonkTechie heartily welcomes you in A Short Note Series (In Which Order Custom Code Executes At Launch Time In iOS ?).

In this note series, we will learn about the App Launch Sequence in iOS. We will discuss the order that our custom code executes at launch time in iOS.

So Let’s begin.


Overview

Launching an app involves a complex sequence of steps, most of which UIKit handles automatically. During the launch sequence, UIKit calls methods of our app delegate so we can perform custom tasks. 

In Figure illustrates the sequence of below steps that occur from the time the app is launched until it is considered initialized.

  1. The app is launched, either explicitly by the user or implicitly by the system.
  2. The XCode-provided main function calls UIKit’s UIApplicationMain(_:_:_:_:) function.
  3. The UIApplicationMain(_:_:_:_:) function creates the UIApplication object and our app delegate.
  4. UIKit loads our app’s default interface from the main storyboard or nib file.
  5. UIKit calls our app delegate’s application(_:willFinishLaunchingWithOptions:) method.
  6. This UIKit performs state restoration, which calls for additional methods of our app delegate and view controllers.
  7. UIKit calls our app delegate’s application(_:didFinishLaunchingWithOptions:) method .

When initialization is complete, the system uses either our scene delegates or app delegate to display our UI and manage the life cycle for our app.


Conclusion

In this note series, we understood about the App Launch Sequence in iOS. We discussed the order that our custom code executes at launch time in iOS.

Thanks for reading! I hope you enjoyed and learned about App Launch Sequence concepts in iOS. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolmonkTechie as below link :

You can also follow other website and tutorials of iOS as below links :

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING !!???

A Short Note – How To Perform One-Time Setup For iOS App ?

Hello Readers, CoolMonkTechie heartily welcomes you in A Short Note Series (How To Perform One-Time Setup For iOS App ?).

In this note series, we will learn about how to perform one-time setup for iOS application. We will discuss how to ensure proper configuration of our app environment.

So Let’s begin.


Overview

When the user launches our app for the first time, we might want to prepare our app environment by performing some one-time tasks. For example, we might want to:

  • Download required data from our server.
  • Copy document templates or modifiable data files from our app bundle to a writable directory.
  • Configure default preferences for the user.
  • Set up user accounts or gather other required data.

Perform any one-time tasks in our app delegate’s application(_:willFinishLaunchingWithOptions:) or application(_:didFinishLaunchingWithOptions:) method. Never block the app’s main thread for tasks that do not require user input. Instead, start tasks asynchronously using a dispatch queue, and let them run in the background while our app finishes launching. For tasks that require user input, make all changes to our user interface in the application(_:didFinishLaunchingWithOptions:) method.


Install Files in the Proper Locations

Our app has its own container directory for storing files, and we should always place app-specific files in the ~/Library subdirectory. Specifically, store our files in the following ~/Library subdirectories:

  • ~/Library/Application Support/—Store app-specific files that we want backed up with the user’s other content. (We can create custom subdirectories here as needed.) Use this directory for data files, configuration files, document templates, and so on.
  • ~/Library/Caches/—Store temporary data files that can be easily regenerated or downloaded.

To obtain a URL for one of the directories in our app’s container, use the urls(for:in:) method of FileManager.

let appSupportURL = FileManager.default.urls(for: 
      .applicationSupportDirectory, in: .userDomainMask)

let cachesURL = FileManager.default.urls(for: 
      .cachesDirectory, in: .userDomainMask)

Place any temporary files in our app’s tmp/ directory. Temporary files might include compressed files that we intend to delete once their contents have been extracted and installed elsewhere. Retrieve the URL for our app’s temporary directory using the temporaryDirectory method of FileManager.


Conclusion

In this note series, we understood how to perform one-time setup for iOS application. We also discussed how to ensure proper configuration of our app environment.

Thanks for reading! I hope you enjoyed and learned about Proper App Environment Configuration concepts in iOS. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolmonkTechie as below link :

You can also follow other website and tutorials of iOS as below links :

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING !!???

iOS – How To Respond To The Application Launch In iOS ?

Hello Readers, CoolMonkTechie heartily welcomes you in this article (How To Respond To The Application Launch In iOS ?).

In this article, We will learn how to respond to the application launch in iOS. We will discuss about initialize our app’s data structures, prepare our app to run, and respond to any launch-time requests from the system in iOS. We also describe why the app launched in iOS.

A famous quote about learning is :

” Research shows that you begin learning in the womb and go right on learning until the moment you pass on. Your brain has a capacity for learning that is virtually limitless, which makes every human a potential genius. “

So Let’s begin.


Overview

The system launches our app when the user taps our app’s icon on the Home screen. If our app requested specific events, the system might also launch our app in the background to handle those events. For a scene-based app, the system similarly launches the app when one of our scenes needs to appear onscreen or do some work.

All apps have an associated process, which the UIApplication object represents. Apps also have an app delegate object—an object that conforms to the UIApplicationDelegate protocol—which responds to important events happening within that process. Even a scene-based app uses an app delegate to manage fundamental events like launch and termination. At launch time, UIKit automatically creates the UIApplication object and our app delegate. It then starts our app’s main event loop.


Provide a Launch Storyboard

When the user first launches the app on a device, the system displays the launch storyboard until the app is ready to display its UI. Displaying the launch storyboard assures the user that our app launched and is doing something. If our app initializes itself and readies its UI quickly, the user may see the launch storyboard only briefly.

Xcode projects automatically include a default launch storyboard for us to customize, and we can add more launch storyboards as necessary. To add new launch storyboards to our project, do the following:

  1. Open your project in Xcode.
  2. Choose File > New > File.
  3. Add a Launch Screen resource to our project.

Add views to our launch storyboard and use Auto Layout constraints to size and position them so that they adapt to the underlying environment. UIKit displays exactly what we provide, using our constraints to fit our views into the available space. We can use  Human Interface Guidelines for for design guidance.

In iOS 13 and later, always provide a launch storyboard for your app. Don’t use static launch images.


Initialize App’s Data Structures

We put our app’s launch-time initialization code in one or both of the following methods:

  • application(_:willFinishLaunchingWithOptions:)
  • application(_:didFinishLaunchingWithOptions:)

UIKit calls these methods at the beginning of our app’s launch cycle. We use them to:

  • Initialize our app’s data structures.
  • Verify that our app has the resources it needs to run.
  • Perform any one-time setup when our app launches for the first time. For example, install templates or user-modifiable files in a writable directory.
  • Connect to any critical services that our app uses. For example, connect to the Apple Push Notification service if our app supports remote notifications.
  • Check the launch options dictionary for information about why our app launched.

For apps that aren’t scene-based, UIKit loads our default user interface automatically at launch time. Use the application(_:didFinishLaunchingWithOptions:) method to make additional changes to that interface before it appears onscreen. For example, we might install a different view controller to reflect what the user was doing the last time they used the app.


Move Long-Running Tasks off the Main Thread

When the user launches the app, make a good impression by launching quickly. UIKit doesn’t present the app’s interface until after the application(_:didFinishLaunchingWithOptions:) method returns. Performing long-running tasks in that method or the application(_:willFinishLaunchingWithOptions:) method might make the app appear sluggish to the user. Returning quickly is also important when launching to the background because the system limits the app’s background execution time.

Move tasks that are not critical to the app’s initialization out of the launch-time sequence. For example:

  • Defer the initialization of features that the app doesn’t need immediately.
  • Move important, long-running tasks off the app’s main thread. For example, run them asynchronously on a global dispatch queue.


Determine Why App Launched

When UIKit launches the app, it passes along a launch options dictionary to the application(_:willFinishLaunchingWithOptions:) and application(_:didFinishLaunchingWithOptions:) methods with information about why the app launched. The keys in that dictionary indicate important tasks to perform immediately. For example, they might reflect actions that the user started elsewhere and wants to continue in the app. Always check the contents of the launch options dictionary for keys that we expect, and respond appropriately to their presence.

For a scene-based app, examine the options that UIKit passes to the application(_:configurationForConnecting:options:) method to determine why it created the scene.

The example shows the app delegate method for an app that handles background location updates. When the location key is present, the app starts location updates immediately instead of deferring them until later. Starting location updates allows the Core Location framework to deliver the new location event.

class AppDelegate: UIResponder, UIApplicationDelegate, 
               CLLocationManagerDelegate {
    
   let locationManager = CLLocationManager()
   func application(_ application: UIApplication,
              didFinishLaunchingWithOptions launchOptions:
              [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
       
      // If launched because of new location data,
      //  start the visits service right away.
      if let keys = launchOptions?.keys {
         if keys.contains(.location) {
            locationManager.delegate = self
            locationManager.startMonitoringVisits()
         }
      }
       
      return true
   }
   // other methods…
}

The system doesn’t include a key unless our app supports the corresponding feature. For example, the system doesn’t include the remoteNotification key for an app that doesn’t support remote notifications.

That’s all about in this article.


Conclusion

In this article, We understood how to respond to the application launch in iOS. This article described about initialize our app’s data structures, prepare our app to run, and respond to any launch-time requests from the system in iOS.

Thanks for reading ! I hope you enjoyed and learned about the Application Launch Concepts in iOS. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolmonkTechie as below link :

You can also follow other website and tutorials of iOS as below links :

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING!!???

React Native – How To Implement Animations Using The Animated API In React Native ?

Hello Readers, CoolMonkTechie heartily welcomes you in this article (How To Implement Animations Using The Animated API In React Native ?).

In this article, We will learn how to implement animations using the animated api in react native platform. Animation is an important part of user experience design. It serves as feedback on user actions, informs users of system status, and guides them on how to interact with the interface.  This article demonstrates the practical implementation of Animations in React native application. The recommended way to animate in React Native for most cases is by using the Animated API.

A famous quote about learning is :

” He who laughs most, learns best. “


So Let’s begin.


Animation Methods

There are three main Animated methods that we can use to create animations:

  1. Animated.timing() — Maps time range to easing value.
  2. Animated.decay() — starts with an initial velocity and gradually slows to a stop.
  3. Animated.spring() — Simple single-spring physics model (Based on Rebound and Origami). Tracks velocity state to create fluid motions as the toValue updates, and can be chained together.

Along with these three Animated methods, there are three ways to call these animations along with calling them individually. We will be covering all three of these as well:

  1. Animated.parallel() — Starts an array of animations all at the same time.
  2. Animated.sequence() — Starts an array of animations in order, waiting for each to complete before starting the next. If the current running animation is stopped, no following animations will be started.
  3. Animated.stagger() — Array of animations may run in parallel (overlap), but are started in sequence with successive delays. Very similar to Animated.parallel() but allows us to add delays to the animations.


1. Animated.timing()


1.1 Animated.timing Basic Example

The first animation we will be creating is this spinning animation using Animated.timing().

// Example implementation:
Animated.timing(
  someValue,
  {
    toValue: number,
    duration: number,
    easing: easingFunction,
    delay: number
  }
)

This type of infinite animation can be useful to use when creating loading indicators, and is one of the more useful animations that we’ve used in many of React Native projects. This concept can also be used to create infinite animations of other types such as scaling up and down or some other type to indicate loading.

To get started, we need to either start with a new React Native project or with a blank existing React Native project. To get started with a new project, type react-native init and the name of the project in the folder in which we will be working in and then cd into that directory:

react-native init animations
cd animations

Now that we are in this folder, open the index.js  file. Now that we have a new project created, the first thing we will need to do is import AnimatedImage, and Easing from react-native below View that is already being imported:

import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  Animated,
  Image,
  Easing
} from 'react-native'

Animated is the library we will be using to create the animations, and ships with React Native.

Image is needed so we can create an image in our UI.

Easing is a module that also ships with React Native. It allows us to use various predefined easing methods such as lineareasequadcubicsinelasticbouncebackbezierinoutinout, and others. We will be using linear as to have a consistent linear motion. We will have a better idea of how to implement them after this section is finished.

Next, we need to set an initial animated value for our spinning value. To do this, we will set the value in our constructor:

constructor () {
  super()
  this.spinValue = new Animated.Value(0)
}

We declare spinValue as a new Animated.Value and pass in 0 (zero). Next, we need to create a spin method and call this method on componentDidMount to get it going when the app loads:

componentDidMount () {
  this.spin()
}
spin () {
  this.spinValue.setValue(0)
  Animated.timing(
    this.spinValue,
    {
      toValue: 1,
      duration: 4000,
      easing: Easing.linear
    }
  ).start(() => this.spin())
}

Here, this spin() method does the following steps:

  1. Sets this.spinValue back to zero
  2. Calls the Animated.timing method and animates this.spinValue to a value of 1 with a duration of 4000 milliseconds and an easing of Easing.linearAnimated.timing takes two arguments, a value (this.spinValue) and a config object. This config object can take a toValue, a duration, an easing method, and a delay.
  3. We call start() on this Animated.timing method, and pass in a callback of this.spin which will be called when the animation is completed, basically creating an infinite animation. start() takes a completion callback that will be called when the animation is done. If the animation is done because it finished running normally, the completion callback will be invoked with {finished: true}, but if the animation is done because stop was called on it before it could finish (e.g. because it was interrupted by a gesture or another animation), then it will receive {finished: false}.

Now that our methods are set up, we need to render the animation in our UI. To do so, we need to update our render method:

render () {
  const spin = this.spinValue.interpolate({
    inputRange: [0, 1],
    outputRange: ['0deg', '360deg']
  })
  return (
    <View style={styles.container}>
      <Animated.Image
        style={{
          width: 227,
          height: 200,
          transform: [{rotate: spin}] }}
          source={{uri: 'https://s3.amazonaws.com/media-p.slid.es/uploads/images/1198519/reactjs.png'}}
      />
    </View>
  )
}

Here, the render() method does the following steps:

  1. We create a variable named spin. In this variable we call interpolate() on this.spinValueinterpolate() is a method that is available to be called on any Animated.Value. interpolate is a method that interpolates the value before updating the property, e.g. mapping 0–1 to 0–10. So in our example, we need to map 0 (zero) degrees to 360 degrees numerically, using the numbers zero to one, and this method easily allows us to do this. We pass in an inputRange and outputRange array, and pass in [0,1] as the inputRange and [‘0deg’, ‘360deg’] as the outputRange.
  2. We return a View with a style of container, and an Animated.Image (React logo) with a heightwidth, and a transform property in which we attach our spin value to the rotate property, which is where the animation takes place:
transform: [{rotate: spin}]

Finally, we have the container style to center everything:

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  }
})

That’s it, the animation should be working now!

The final code for this animation with a working example is :

index.js

import React, { Component } from 'react'
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  Animated,
  Image,
  Easing
} from 'react-native'

const timing = 4000

class animations extends Component {
  constructor () {
    super()
    this.spinValue = new Animated.Value(0)
  }
  componentDidMount () {
    this.spin()
  }
  spin () {
    this.spinValue.setValue(0)
    Animated.timing(
      this.spinValue,
      {
        toValue: 1,
        duration: timing,
        easing: Easing.linear
      }
    ).start(() => this.spin())
  }
  render () {
    /* This also works, to show functions instead of strings */
    // const getStartValue = () => '0deg'
    // const getEndValue = () => '360deg'
    // const spin = this.spinValue.interpolate({
    //   inputRange: [0, 1],
    //   outputRange: [getStartValue(), getEndValue()]
    // })
    const spin = this.spinValue.interpolate({
      inputRange: [0, 1],
      outputRange: ['0deg', '360deg']
    })
    return (
      <View style={styles.container}>
        <Animated.Image
          style={{ width: 227, height: 200, transform: [{rotate: spin}] }}
          source={{uri: 'https://s3.amazonaws.com/media-p.slid.es/uploads/images/1198519/reactjs.png'}}/>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  }
})

AppRegistry.registerComponent('animations', () => animations)

Note that – Use own image url for example code testing.

The output of the above example is :


1.2 Animated.timing multiple animation Example

Now that we know the basics of Animated.timing, let’s take a look at a few more examples of how to use Animated.timing along with interpolate and declare some other animations.

In the next example, we will declare a single animation value, this.animatedValue, and use the single animated value along with interpolate to create multiple animations, animating the following style properties:

  1. marginLeft
  2. opacity
  3. fontSize
  4. rotateX

To get started, either begin with a new branch or clear out our old code from the last project.

The first thing we will do is create the animated value that we will be using for these animations in the constructor:

constructor () {
  super()
  this.animatedValue = new Animated.Value(0)
}

Next, we create the animate method and call it in componentDidMount() :

componentDidMount () {
  this.animate()
}
animate () {
  this.animatedValue.setValue(0)
  Animated.timing(
    this.animatedValue,
    {
      toValue: 1,
      duration: 2000,
      easing: Easing.linear
    }
  ).start(() => this.animate())
}

In the render method, we create 5 different interpolated value variables:

render () { 
  const marginLeft = this.animatedValue.interpolate({
    inputRange: [0, 1],
    outputRange: [0, 300]
  })
  const opacity = this.animatedValue.interpolate({
    inputRange: [0, 0.5, 1],
    outputRange: [0, 1, 0]
  })
  const movingMargin = this.animatedValue.interpolate({
    inputRange: [0, 0.5, 1],
    outputRange: [0, 300, 0]
  })
  const textSize = this.animatedValue.interpolate({
    inputRange: [0, 0.5, 1],
    outputRange: [18, 32, 18]
  })
  const rotateX = this.animatedValue.interpolate({
    inputRange: [0, 0.5, 1],
    outputRange: ['0deg', '180deg', '0deg']
  })
...
}

interpolate is a very powerful method, allowing us to use this.animatedValue , a single animated value, in many ways. Because the value simply changes from zero to one, we are able to interpolate this property for styling opacity, margins, text sizes, and rotation properties.

We then return Animated.View and Animated.Text components implementing these new variables:

return (
    <View style={styles.container}>
      <Animated.View
        style={{
          marginLeft,
          height: 30,
          width: 40,
          backgroundColor: 'red'}} />
      <Animated.View
        style={{
          opacity,
          marginTop: 10,
          height: 30,
          width: 40,
          backgroundColor: 'blue'}} />
      <Animated.View
        style={{
          marginLeft: movingMargin,
          marginTop: 10,
          height: 30,
          width: 40,
          backgroundColor: 'orange'}} />
      <Animated.Text
        style={{
          fontSize: textSize,
          marginTop: 10,
          color: 'green'}} >
          Animated Text!
      </Animated.Text>
      <Animated.View
        style={{
          transform: [{rotateX}],
          marginTop: 50,
          height: 30,
          width: 40,
          backgroundColor: 'black'}}>
        <Text style={{color: 'white'}}>Hello from TransformX</Text>
      </Animated.View>
    </View>
)

We also update our container styling:

const styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingTop: 150
  }
})

That’s it, the animation should be working now!

The final code for this animation with a working example is :

index.js

import React, { Component } from 'react'
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  Animated,
  Image,
  Easing
} from 'react-native'

class animations extends Component {
  constructor () {
    super()
    this.animatedValue = new Animated.Value(0)
  }
  componentDidMount () {
    this.animate()
  }
  animate () {
    this.animatedValue.setValue(0)
    Animated.timing(
      this.animatedValue,
      {
        toValue: 1,
        duration: 2000,
        easing: Easing.linear
      }
    ).start(() => this.animate())
  }
  render () {
    const marginLeft = this.animatedValue.interpolate({
      inputRange: [0, 1],
      outputRange: [0, 300]
    })
    const opacity = this.animatedValue.interpolate({
      inputRange: [0, 0.5, 1],
      outputRange: [0, 1, 0]
    })
    const movingMargin = this.animatedValue.interpolate({
      inputRange: [0, 0.5, 1],
      outputRange: [0, 300, 0]
    })
    const textSize = this.animatedValue.interpolate({
      inputRange: [0, 0.5, 1],
      outputRange: [18, 32, 18]
    })
    const rotateX = this.animatedValue.interpolate({
      inputRange: [0, 0.5, 1],
      outputRange: ['0deg', '180deg', '0deg']
    })
    return (
      <View style={styles.container}>
        <Animated.View
          style={{
            marginLeft,
            height: 30,
            width: 40,
            backgroundColor: 'red'}} />
        <Animated.View
          style={{
            opacity,
            marginTop: 10,
            height: 30,
            width: 40,
            backgroundColor: 'blue'}} />
        <Animated.View
          style={{
            marginLeft: movingMargin,
            marginTop: 10,
            height: 30,
            width: 40,
            backgroundColor: 'orange'}} />
        <Animated.Text
          style={{
            fontSize: textSize,
            marginTop: 10,
            color: 'green'}} >
            Animated Text!
        </Animated.Text>
        <Animated.View
          style={{
            transform: [{rotateX}],
            marginTop: 50,
            height: 30,
            width: 40,
            backgroundColor: 'black'}}>
          <Text style={{color: 'white'}}>Hello from TransformX</Text>
        </Animated.View>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingTop: 150
  }
})

AppRegistry.registerComponent('animations', () => animations)

The output of the above example is :


2. Animated.decay()

Decay used to animate the value from its initial velocity down to zero using the deceleration option.

state = {
  animation: new Animated.Value(-150)
}

componentDidMount() {
  Animated.decay(
    this.state.animation,
    {
      toValue: 200,
      duration: 2000,
      velocity: 0.95,
      deceleration: 0.998 // By default equals to 0.997
    }
  ).start();
}

To demonstrate that we are going to use Motion example. In this example, we are moving the box down the screen. Once the box reaches the finishing line at 200 points below the center, the decay effect applies. The box keeps moving, but its speed is slowing down until it stops.

The final code for this animation with a working example is :

import React from 'react';
import { Animated, View } from 'react-native';

export default class App extends React.Component {
  state = {
    animation: new Animated.Value(-150)
  }

  componentDidMount() {
    Animated.decay(
      this.state.animation,
      {
        toValue: 200,
        duration: 2000,
        velocity: 0.95,
        deceleration: 0.998
      }
    ).start();
  }

  render() {
    const animationStyles = {
      transform: [
        { translateY: this.state.animation }
      ]
    };

    return (
      <Animated.View style={[objectStyles.object, animationStyles]}>
      </Animated.View>
    );
  }
}

const objectStyles = {
  object: {
    backgroundColor: 'orange',
    width: 100,
    height: 100
  }
}

The output of the above example is :


3. Animated.spring()

Next, we will be creating an animation using the Animated.spring() method.

// Example implementation:
Animated.spring(
    someValue,
    {
      toValue: number,
      friction: number
    }
)

We can keep going from the same project, we just need to update a few things. In our constructor, let’s create a value called springValue and set it’s value to .3:

constructor () {
  super()
  this.springValue = new Animated.Value(0.3)
}

Next, let’s delete the animate() method and componentDidMount() method and create a new method called spring():

spring () {
  this.springValue.setValue(0.3)
  Animated.spring(
    this.springValue,
    {
      toValue: 1,
      friction: 1
    }
  ).start()
}

Here, this spring() method does the following steps:

  1. We set the springValue to .3 if it’s not already set to .3
  2. We call Animated.spring, passing in two arguments: a value to animate and a config object. The config object can take any of the following arguments: toValue (number), overshootClamping (boolean), restDisplacementThreshold (number), restSpeedThreshold (number), velocity (number), bounciness (number), speed (number), tension (number), and friction (number). The only required value is toValue, but friction and tension can help us get more control over the spring animation.
  3. We call start() to start the animation.

Now that the animation is set up, let’s attach the animation to a click event in our view, and the animation itself to the same React logo we used before:

<View style={styles.container}>
  <Text
    style={{marginBottom: 100}}
    onPress={this.spring.bind(this)}>Spring</Text>
    <Animated.Image
      style={{ width: 227, height: 200, transform: [{scale: this.springValue}] }}
      source={{uri: 'https://s3.amazonaws.com/media-p.slid.es/uploads/images/1198519/reactjs.png'}}/>
</View>

Here, click event code do the following steps :

  1. We return a Text component attached to the spring() method to an onPress event.
  2. We return the Animated image and attach this.springValue to the scale property.

The spring animation should be working now!

The final code for this animation with a working example is :

import React, { Component } from 'react'
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  Animated,
  Image
} from 'react-native'

class animations extends Component {
  constructor () {
    super()
    this.springValue = new Animated.Value(0.3)
  }
  spring () {
    this.springValue.setValue(0.3)
    Animated.spring(
      this.springValue,
      {
        toValue: 1,
        friction: 1,
        tension: 1
      }
    ).start()
  }
  render () {
    return (
      <View style={styles.container}>
        <Text style={{marginBottom: 100}} onPress={this.spring.bind(this)}>Spring</Text>
        <Animated.Image
          style={{ width: 227, height: 200, transform: [{scale: this.springValue}] }}
          source={{uri: 'https://s3.amazonaws.com/media-p.slid.es/uploads/images/1198519/reactjs.png'}}/>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  }
})

AppRegistry.registerComponent('animations', () => animations)

Note that – Use own image url for example code testing.

The output of the above example is :


4. Animated.parallel()

Animated.parallel() starts an array of animations all at the same time.

Let’s take a look at the api and see how this works:

// API
Animated.parallel(arrayOfAnimations)
// In use:
Animated.parallel([
  Animated.spring(
    animatedValue,
    {
      //config options
    }
  ),
  Animated.timing(
     animatedValue2,
     {
       //config options
     }
  )
])

To get started, let’s go ahead and create the three animated values we will need in our constructor:

constructor () {
  super()
  this.animatedValue1 = new Animated.Value(0)
  this.animatedValue2 = new Animated.Value(0)
  this.animatedValue3 = new Animated.Value(0)
}

Next, we create our animate method and call it in componendDidMount() :

componentDidMount () {
  this.animate()
}
animate () {
  this.animatedValue1.setValue(0)
  this.animatedValue2.setValue(0)
  this.animatedValue3.setValue(0)
  const createAnimation = function (value, duration, easing, delay = 0) {
    return Animated.timing(
      value,
      {
        toValue: 1,
        duration,
        easing,
        delay
      }
    )
  }
  Animated.parallel([
    createAnimation(this.animatedValue1, 2000, Easing.ease),
    createAnimation(this.animatedValue2, 1000, Easing.ease, 1000),
    createAnimation(this.animatedValue3, 1000, Easing.ease, 2000)        
  ]).start()
}

In the animate method, we set the values of all three animated values back to zero. We then create a function called createAnimation() which returns a new animation , taking in the value, duration, easing, and delay as arguments. If no delay is passed in, we set it to zero.

We then call Animated.parallel() passing in the three animations we want to create using createAnimation().

In our render method, we next need to set up our interpolated values:

render () {
  const scaleText = this.animatedValue1.interpolate({
    inputRange: [0, 1],
    outputRange: [0.5, 2]
  })
  const spinText = this.animatedValue2.interpolate({
    inputRange: [0, 1],
    outputRange: ['0deg', '720deg']
  })
  const introButton = this.animatedValue3.interpolate({
    inputRange: [0, 1],
    outputRange: [-100, 400]
  })
  ...
}

Here, the render () method code do the following steps :

1. scaleText — We interpolate our values to be output as a range from 0.5 to 2, we will use this value to scale our text from .5 to 2.

2. spinText — We interpolate our values to be output as a range of 0 degrees to 720 degrees, essentially spinning the item two times.

3. introButton — We interpolate out values to be output as a range of -100 to 400, and will use this as a margin property in our View.

Finally, we render a main View with three Animated.Views:

<View style={[styles.container]}>
  <Animated.View 
    style={{ transform: [{scale: scaleText}] }}>
    <Text>Welcome</Text>
  </Animated.View>
  <Animated.View
    style={{ marginTop: 20, transform: [{rotate: spinText}] }}>
    <Text
      style={{fontSize: 20}}>
      to the App!
    </Text>
  </Animated.View>
  <Animated.View
    style={{top: introButton, position: 'absolute'}}>
    <TouchableHighlight
      onPress={this.animate.bind(this)}
      style={styles.button}>
      <Text
        style={{color: 'white', fontSize: 20}}>
        Click Here To Start
      </Text>
   </TouchableHighlight>
  </Animated.View>
</View>

We use scaleText to scale the first View, spinText to spin the second View, and introButton to animate the margin of the third View.

When animate() is called, all three animations run in parallel. The parallel animations should be working now!

The final code for this animation with a working example is :

import React, { Component } from 'react'
import {
  AppRegistry,
  StyleSheet,
  Text,
  Animated,
  View,
  Easing,
  TouchableHighlight,
  Dimensions
} from 'react-native'

const { width } = Dimensions.get('window')

class animations extends Component {

  constructor () {
    super()
    this.animatedValue1 = new Animated.Value(0)
    this.animatedValue2 = new Animated.Value(0)
    this.animatedValue3 = new Animated.Value(0)
  }

  componentDidMount () {
    this.animate()
  }

  animate () {
    this.animatedValue1.setValue(0)
    this.animatedValue2.setValue(0)
    this.animatedValue3.setValue(0)
    const createAnimation = function (value, duration, easing, delay = 0) {
      return Animated.timing(
       value,
        {
          toValue: 1,
          duration,
          easing,
          delay
        }
      )
    }
    Animated.parallel([
      createAnimation(this.animatedValue1, 2000, Easing.ease),
      createAnimation(this.animatedValue2, 1000, Easing.ease, 1000),
      createAnimation(this.animatedValue3, 1000, Easing.ease, 2000)
    ]).start()
  }

  render () {
    const scaleText = this.animatedValue1.interpolate({
      inputRange: [0, 1],
      outputRange: [0.5, 2]
    })
    const spinText = this.animatedValue2.interpolate({
      inputRange: [0, 1],
      outputRange: ['0deg', '720deg']
    })
    const introButton = this.animatedValue3.interpolate({
      inputRange: [0, 1],
      outputRange: [-100, 400]
    })
    return (
      <View style={[styles.container]}>
        <Animated.View style={{ transform: [{scale: scaleText}] }}>
          <Text>Welcome</Text>
        </Animated.View>
        <Animated.View style={{ marginTop: 20, transform: [{rotate: spinText}] }}>
          <Text style={{fontSize: 20}}>to the App!</Text>
        </Animated.View>
        <Animated.View style={{top: introButton, position: 'absolute'}}>
          <TouchableHighlight onPress={this.animate.bind(this)} style={styles.button}>
            <Text style={{color: 'white', fontSize: 20}}>Click Here To Start</Text>
          </TouchableHighlight>
        </Animated.View>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  },
  button: {
    width: width - 40,
    height: 70,
    marginLeft: 20,
    marginRight: 20,
    backgroundColor: 'blue',
    justifyContent: 'center',
    alignItems: 'center'
  }
})

AppRegistry.registerComponent('animations', () => animations)

The output of the above example is :


5. Animated.sequence()

Let’s take a look at the api and see how this animation works:

// API
Animated.sequence(arrayOfAnimations)
// In use
Animated.sequence([
  Animated.timing(
    animatedValue,
    {
      //config options
    }
  ),
  Animated.spring(
     animatedValue2,
     {
       //config options
     }
  )
])

Like Animated.parallel()Animated.sequence() takes an array of animations. Animated.sequence() runs an array of animations in order, waiting for each to complete before starting the next.

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  Animated
} from 'react-native'

const arr = []
for (var i = 0; i < 500; i++) {
  arr.push(i)
}

class animations extends Component {

  constructor () {
    super()
    this.animatedValue = []
    arr.forEach((value) => {
      this.animatedValue[value] = new Animated.Value(0)
    })
  }

  componentDidMount () {
    this.animate()
  }

  animate () {
    const animations = arr.map((item) => {
      return Animated.timing(
        this.animatedValue[item],
        {
          toValue: 1,
          duration: 50
        }
      )
    })
    Animated.sequence(animations).start()
  }

  render () {
    const animations = arr.map((a, i) => {
      return <Animated.View key={i} style={{opacity: this.animatedValue[a], height: 20, width: 20, backgroundColor: 'red', marginLeft: 3, marginTop: 3}} />
    })
    return (
      <View style={styles.container}>
        {animations}
      </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'row',
    flexWrap: 'wrap'
  }
})

AppRegistry.registerComponent('animations', () => animations);

Because the apis for Animated.sequence() and Animated.parallel() are so similar, taking an array of animations, we are not going to repeat the walkthrough of each method.

The main thing to notice here that is different is that we are creating our Animated.Values with a loop since we are animating so many values. We are also rendering our Animated.Views with a map function returning a new Animated.View for each item in the array.

The sequence of animations should be working now! The output of the above example is :


6. Animated.stagger()

Let’s take a look at the api and see how this animation works:

// API
Animated.stagger(delay, arrayOfAnimations)
// In use:
Animated.stagger(1000, [
  Animated.timing(
    animatedValue,
    {
      //config options
    }
  ),
  Animated.spring(
     animatedValue2,
     {
       //config options
     }
  )
])

Like Animated.parallel() and Animated.sequence(), Animated.Stagger also takes an array of animations, but these animations are started in sequence with successive delays.

The main difference here is the first argument, the delay that will be applied to each animation.

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  Animated
} from 'react-native'

const arr = []
for (var i = 0; i < 500; i++) {
  arr.push(i)
}

class animations extends Component {

  constructor () {
    super()
    this.animatedValue = []
    arr.forEach((value) => {
      this.animatedValue[value] = new Animated.Value(0)
    })
  }

  componentDidMount () {
    this.animate()
  }

  animate () {
    const animations = arr.map((item) => {
      return Animated.timing(
        this.animatedValue[item],
        {
          toValue: 1,
          duration: 4000
        }
      )
    })
    Animated.stagger(10, animations).start()
  }

  render () {
    const animations = arr.map((a, i) => {
      return <Animated.View key={i} style={{opacity: this.animatedValue[a], height: 20, width: 20, backgroundColor: 'red', marginLeft: 3, marginTop: 3}} />
    })
    return (
      <View style={styles.container}>
        {animations}
      </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'row',
    flexWrap: 'wrap'
  }
})

AppRegistry.registerComponent('animations', () => animations);

The staggered animations should be working now! The output of above example is :

That’s all about in this article.


Conclusion

In this article, We understood about Animation Animation Animated API in React Native. Animation is an important part of user experience design. It serves as feedback on user actions, informs users of system status, and guides them on how to interact with the interface. We discussed how to implement Animations using Animated Api in React native with some example.

Thanks for reading ! I hope you enjoyed and learned about the Animation Animated API Concepts in React Native. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolmonkTechie as below link :

You can also follow official website and tutorials of React Native as below links :

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING!!???

React Native – Understanding Animations In React Native

Hello Readers, CoolMonkTechie heartily welcomes you in this article (Understanding Animations In React Native).

In this article, We will learn about Animations in React Native. Animations are very important to create a great user experience. Stationary objects must overcome inertia as they start moving. Objects in motion have momentum and rarely come to a stop immediately. Animations allow us to convey physically believable motion in our interface.

A famous quote about learning is :

” Develop a passion for learning. If you do, you will never cease to grow.”

So Let’s begin.


Animation Systems

React Native provides two complementary animation systems: 

  • Animated for granular and interactive control of specific values. It is a built-in API for animating component styles.
  • LayoutAnimation for animated global layout transactions. It is a built-in API for animating between 2 component hierarchies (think “magic move”), although still considered experimental.

Most animations will use Animated.


1. Animated

The Animated API is designed to concisely express a wide variety of interesting animation and interaction patterns in a very performant way. Animated focuses on declarative relationships between inputs and outputs, with configurable transforms in between, and start/stop methods to control time-based animation execution.

Animated exports six animatable component types: ViewTextImageScrollViewFlatList and SectionList, but we can also create own using Animated.createAnimatedComponent().

The Animated API lets us animate component styles.

For example, a container view that fades in when it is mounted may look like this:

import React, { useRef, useEffect } from 'react';
import { Animated, Text, View } from 'react-native';

const FadeInView = (props) => {
  const fadeAnim = useRef(new Animated.Value(0)).current  // Initial value for opacity: 0

  React.useEffect(() => {
    Animated.timing(
      fadeAnim,
      {
        toValue: 1,
        duration: 10000,
      }
    ).start();
  }, [fadeAnim])

  return (
    <Animated.View                 // Special animatable View
      style={{
        ...props.style,
        opacity: fadeAnim,         // Bind opacity to animated value
      }}
    >
      {props.children}
    </Animated.View>
  );
}

// You can then use your `FadeInView` in place of a `View` in your components:
export default () => {
  return (
    <View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
      <FadeInView style={{width: 250, height: 50, backgroundColor: 'powderblue'}}>
        <Text style={{fontSize: 28, textAlign: 'center', margin: 10}}>Fading in</Text>
      </FadeInView>
    </View>
  )
}

Let’s break down what’s happening here.  In the FadeInView constructor, a new Animated.Value called fadeAnim is initialized as part of state. The opacity property on the View is mapped to this animated value. Behind the scenes, the numeric value is extracted and used to set opacity.

When the component mounts, the opacity is set to 0. Then, an easing animation is started on the fadeAnim animated value, which will update all of its dependent mappings (in this case, only the opacity) on each frame as the value animates to the final value of 1.

This is done in an optimized way that is faster than calling setState and re-rendering. Because the entire configuration is declarative, we will be able to implement further optimizations that serialize the configuration and runs the animation on a high-priority thread.


Configuring animations

Animations are heavily configurable. Custom and predefined easing functions, delays, durations, decay factors, spring constants, and more can all be tweaked depending on the type of animation.

Animated provides several animation types, the most commonly used one being Animated.timing(). It supports animating a value over time using one of various predefined easing functions, or we can use own. Easing functions are typically used in animation to convey gradual acceleration and deceleration of objects.

By default, timing will use an easeInOut curve that conveys gradual acceleration to full speed and concludes by gradually decelerating to a stop. We can specify a different easing function by passing an easing parameter. Custom duration or even a delay before the animation starts is also supported.

For example, if we want to create a 2-second long animation of an object that slightly backs up before moving to its final position:

Animated.timing(this.state.xPosition, {
  toValue: 100,
  easing: Easing.back(),
  duration: 2000
}).start();


Composing animations

Animations can be combined and played in sequence or in parallel. Sequential animations can play immediately after the previous animation has finished, or they can start after a specified delay. The Animated API provides several methods, such as sequence() and delay(), each of which take an array of animations to execute and automatically calls start()/stop() as needed.

For example, the following animation coasts to a stop, then it springs back while twirling in parallel:

Animated.sequence([
  // decay, then spring to start and twirl
  Animated.decay(position, {
    // coast to a stop
    velocity: { x: gestureState.vx, y: gestureState.vy }, // velocity from gesture release
    deceleration: 0.997
  }),
  Animated.parallel([
    // after decay, in parallel:
    Animated.spring(position, {
      toValue: { x: 0, y: 0 } // return to start
    }),
    Animated.timing(twirl, {
      // and twirl
      toValue: 360
    })
  ])
]).start(); // start the sequence group

If one animation is stopped or interrupted, then all other animations in the group are also stopped. Animated.parallel has a stopTogether option that can be set to false to disable this.


Combining animated values

We can combine two animated values via addition, multiplication, division, or modulo to make a new animated value.

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 = new Animated.Value(1);
const b = Animated.divide(1, a);

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


Interpolation

Each property can be run through an interpolation first. An interpolation maps input ranges to output ranges, typically using a linear interpolation but also supports easing functions. By default, it will extrapolate the curve beyond the ranges given, but we can also have it clamp the output value.

A basic mapping to convert a 0-1 range to a 0-100 range would be:

value.interpolate({
  inputRange: [0, 1],
  outputRange: [0, 100]
});

For example, we may want to think about our Animated.Value as going from 0 to 1, but animate the position from 150px to 0px and the opacity from 0 to 1. This can be done by modifying style from the example above like so:

style={{
    opacity: this.state.fadeAnim, // Binds directly
    transform: [{
      translateY: this.state.fadeAnim.interpolate({
        inputRange: [0, 1],
        outputRange: [150, 0]  // 0 : 150, 0.5 : 75, 1 : 0
      }),
    }],
  }}

interpolate() supports multiple range segments as well, which is handy for defining dead zones and other handy tricks. For example, to get a negation relationship at -300 that goes to 0 at -100, then back up to 1 at 0, and then back down to zero at 100 followed by a dead-zone that remains at 0 for everything beyond that, we could do:

value.interpolate({
  inputRange: [-300, -100, 0, 100, 101],
  outputRange: [300, 0, 1, 0, 0]
});

Which would map like so:

Input | Output
------|-------
  -400|    450
  -300|    300
  -200|    150
  -100|      0
   -50|    0.5
     0|      1
    50|    0.5
   100|      0
   101|      0
   200|      0

interpolate() also supports mapping to strings, allowing us to animate colors as well as values with units. For example, if we wanted to animate a rotation we could do:

value.interpolate({
  inputRange: [0, 360],
  outputRange: ['0deg', '360deg']
});

interpolate() also supports arbitrary easing functions, many of which are already implemented in the Easing module. interpolate() also has configurable behavior for extrapolating the outputRange. We can set the extrapolation by setting the extrapolateextrapolateLeft, or extrapolateRight options. The default value is extend but we can use clamp to prevent the output value from exceeding outputRange.


Tracking dynamic values

Animated values can also track other values by setting the toValue of an animation to another animated value instead of a plain number. For example, a “Chat Heads” animation like the one used by Messenger on Android could be implemented with a spring() pinned on another animated value, or with timing() and a duration of 0 for rigid tracking. They can also be composed with interpolations:

Animated.spring(follower, { toValue: leader }).start();
Animated.timing(opacity, {
  toValue: pan.x.interpolate({
    inputRange: [0, 300],
    outputRange: [1, 0]
  })
}).start();

The leader and follower animated values would be implemented using Animated.ValueXY()ValueXY is a handy way to deal with 2D interactions, such as panning or dragging. It is a basic wrapper that contains two Animated.Value instances and some helper functions that call through to them, making ValueXY a drop-in replacement for Value in many cases. It allows us to track both x and y values in the example above.


Tracking gestures

Gestures, like panning or scrolling, and other events can map directly to animated values using Animated.event. This is done with a structured map syntax so that values can be extracted from complex event objects. The first level is an array to allow mapping across multiple args, and that array contains nested objects.

For example, when working with horizontal scrolling gestures, we would do the following in order to map event.nativeEvent.contentOffset.x to scrollX (an Animated.Value):

onScroll={Animated.event(
   // scrollX = e.nativeEvent.contentOffset.x
   [{ nativeEvent: {
        contentOffset: {
          x: scrollX
        }
      }
    }]
 )}

The following example implements a horizontal scrolling carousel where the scroll position indicators are animated using the Animated.event used in the ScrollView.

import React, { useRef } from "react";
import {
  SafeAreaView,
  ScrollView,
  Text,
  StyleSheet,
  View,
  ImageBackground,
  Animated,
  useWindowDimensions
} from "react-native";

const images = new Array(6).fill('https://images.unsplash.com/photo-1556740749-887f6717d7e4');

const App = () => {
  const scrollX = useRef(new Animated.Value(0)).current;

  const { width: windowWidth } = useWindowDimensions();

  return (
    <SafeAreaView style={styles.container}>
      <View style={styles.scrollContainer}>
        <ScrollView
          horizontal={true}
          style={styles.scrollViewStyle}
          pagingEnabled
          showsHorizontalScrollIndicator={false}
          onScroll={Animated.event([
            {
              nativeEvent: {
                contentOffset: {
                  x: scrollX
                }
              }
            }
          ])}
          scrollEventThrottle={1}
        >
          {images.map((image, imageIndex) => {
            return (
              <View
                style={{ width: windowWidth, height: 250 }}
                key={imageIndex}
              >
                <ImageBackground source={{ uri: image }} style={styles.card}>
                  <View style={styles.textContainer}>
                    <Text style={styles.infoText}>
                      {"Image - " + imageIndex}
                    </Text>
                  </View>
                </ImageBackground>
              </View>
            );
          })}
        </ScrollView>
        <View style={styles.indicatorContainer}>
          {images.map((image, imageIndex) => {
            const width = scrollX.interpolate({
              inputRange: [
                windowWidth * (imageIndex - 1),
                windowWidth * imageIndex,
                windowWidth * (imageIndex + 1)
              ],
              outputRange: [8, 16, 8],
              extrapolate: "clamp"
            });
            return (
              <Animated.View
                key={imageIndex}
                style={[styles.normalDot, { width }]}
              />
            );
          })}
        </View>
      </View>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center"
  },
  scrollContainer: {
    height: 300,
    alignItems: "center",
    justifyContent: "center"
  },
  card: {
    flex: 1,
    marginVertical: 4,
    marginHorizontal: 16,
    borderRadius: 5,
    overflow: "hidden",
    alignItems: "center",
    justifyContent: "center"
  },
  textContainer: {
    backgroundColor: "rgba(0,0,0, 0.7)",
    paddingHorizontal: 24,
    paddingVertical: 8,
    borderRadius: 5
  },
  infoText: {
    color: "white",
    fontSize: 16,
    fontWeight: "bold"
  },
  normalDot: {
    height: 8,
    width: 8,
    borderRadius: 4,
    backgroundColor: "silver",
    marginHorizontal: 4
  },
  indicatorContainer: {
    flexDirection: "row",
    alignItems: "center",
    justifyContent: "center"
  }
});

export default App;

The output of the above example is :

When using PanResponder, we could use the following code to extract the x and y positions from gestureState.dx and gestureState.dy. We use a null in the first position of the array, as we are only interested in the second argument passed to the PanResponder handler, which is the gestureState.

onPanResponderMove={Animated.event(
  [null, // ignore the native event
  // extract dx and dy from gestureState
  // like 'pan.x = gestureState.dx, pan.y = gestureState.dy'
  {dx: pan.x, dy: pan.y}
])}


Responding to the current animation value

We may notice that there is no clear way to read the current value while animating. This is because the value may only be known in the native runtime due to optimizations. If we need to run JavaScript in response to the current value, there are two approaches:

  • spring.stopAnimation(callback) will stop the animation and invoke callback with the final value. This is useful when making gesture transitions.
  • spring.addListener(callback) will invoke callback asynchronously while the animation is running, providing a recent value. This is useful for triggering state changes, for example snapping a bobble to a new option as the user drags it closer, because these larger state changes are less sensitive to a few frames of lag compared to continuous gestures like panning which need to run at 60 fps.

Animated is designed to be fully serializable so that animations can be run in a high performance way, independent of the normal JavaScript event loop. This does influence the API, so keep that in mind when it seems a little trickier to do something compared to a fully synchronous system. We need to check out Animated.Value.addListener as a way to work around some of these limitations, but use it sparingly since it might have performance implications in the future.


Using the native driver

The Animated API is designed to be serializable. By using the native driver, we send everything about the animation to native before starting the animation, allowing native code to perform the animation on the UI thread without having to go through the bridge on every frame. Once the animation has started, the JS thread can be blocked without affecting the animation.

Using the native driver for normal animations is straightforward. We can add useNativeDriver: true to the animation config when starting it.

Animated.timing(this.state.animatedValue, {
  toValue: 1,
  duration: 500,
  useNativeDriver: true // <-- Add this
}).start();

Animated values are only compatible with one driver so if we use native driver when starting an animation on a value, make sure every animation on that value also uses the native driver.

The native driver also works with Animated.event. This is especially useful for animations that follow the scroll position as without the native driver, the animation will always run a frame behind the gesture due to the async nature of React Native.

<Animated.ScrollView // <-- Use the Animated ScrollView wrapper
  scrollEventThrottle={1} // <-- Use 1 here to make sure no events are ever missed
  onScroll={Animated.event(
    [
      {
        nativeEvent: {
          contentOffset: { y: this.state.animatedValue }
        }
      }
    ],
    { useNativeDriver: true } // <-- Add this
  )}>
  {content}
</Animated.ScrollView>

Not everything we can do with Animated is currently supported by the native driver. The main limitation is that we can only animate non- layout properties: things like transform and opacity will work, but Flexbox and position properties will not. When using Animated.event, it will only work with direct events and not bubbling events. This means it does not work with PanResponder but does work with things like ScrollView#onScroll.

When an animation is running, it can prevent VirtualizedList components from rendering more rows. If we need to run a long or looping animation while the user is scrolling through a list, we can use isInteraction: false in our animation’s config to prevent this issue.


2. LayoutAnimation API

LayoutAnimation allows us to globally configure create and update animations that will be used for all views in the next render/layout cycle. This is useful for doing Flexbox layout updates without bothering to measure or calculate specific properties in order to animate them directly, and is especially useful when layout changes may affect ancestors, for example a “see more” expansion that also increases the size of the parent and pushes down the row below which would otherwise require explicit coordination between the components in order to animate them all in sync.

Note that although LayoutAnimation is very powerful and can be quite useful, it provides much less control than Animated and other animation libraries, so we may need to use another approach if we can’t get LayoutAnimation to do what you want.

Note that in order to get this to work on Android, we need to set the following flags via UIManager:

UIManager.setLayoutAnimationEnabledExperimental &&
  UIManager.setLayoutAnimationEnabledExperimental(true);

This example uses a preset value, we can customize the animations as we need,

import React from 'react';
import {
  NativeModules,
  LayoutAnimation,
  Text,
  TouchableOpacity,
  StyleSheet,
  View,
} from 'react-native';

const { UIManager } = NativeModules;

UIManager.setLayoutAnimationEnabledExperimental &&
  UIManager.setLayoutAnimationEnabledExperimental(true);

export default class App extends React.Component {
  state = {
    w: 100,
    h: 100,
  };

  _onPress = () => {
    // Animate the update
    LayoutAnimation.spring();
    this.setState({ w: this.state.w + 15, h: this.state.h + 15 })
  }

  render() {
    return (
      <View style={styles.container}>
        <View style={[styles.box, { width: this.state.w, height: this.state.h }]} />
        <TouchableOpacity onPress={this._onPress}>
          <View style={styles.button}>
            <Text style={styles.buttonText}>Press me!</Text>
          </View>
        </TouchableOpacity>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  box: {
    width: 200,
    height: 200,
    backgroundColor: 'red',
  },
  button: {
    backgroundColor: 'black',
    paddingHorizontal: 20,
    paddingVertical: 15,
    marginTop: 15,
  },
  buttonText: {
    color: '#fff',
    fontWeight: 'bold',
  },
});

The output of the above example is :

That’s all about in this article.

Related Other Articles / Posts


Conclusion

In this article, We understood about Animations in React Native. Animation is an important part of user experience design. It serves as feedback on user actions, informs users of system status, and guides them on how to interact with the interface. 

Thanks for reading ! I hope you enjoyed and learned about the Animations Concepts in React Native. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolmonkTechie as below link :

You can also follow official website and tutorials of React Native as below links :

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING!!???

React Native – How To Use Touchable Components In React Native ?

Hello Readers, CoolMonkTechie heartily welcomes you in this article (React Native – How To Use Touchable Components In React Native?).

In this article, we will understand about how to use Touchable Components in React Native. Users interact with mobile apps mainly through touch. They can use a combination of gestures, such as tapping on a button, scrolling a list, or zooming on a map. React Native provides components to handle all sorts of common gestures, as well as a comprehensive gesture responder system to allow for more advanced gesture recognition, but the one component we will most likely be interested in is the basic Button. This article demonstrates the kinds of touchable with examples in React Native.

A famous quote about learning is :

” Anyone who stops learning is old, whether at twenty or eighty. Anyone who keeps learning stays young. The greatest thing in life is to keep your mind young. “

So Let’s begin.


Displaying a basic button

Button provides a basic button component that is rendered nicely on all platforms. The minimal example to display a button looks like this:

<Button
  onPress={() => {
    alert('You tapped the button!');
  }}
  title="Press Me"
/>

This will render a blue label on iOS, and a blue rounded rectangle with light text on Android. Pressing the button will call the “onPress” function, which in this case displays an alert popup. If we like, we can specify a “color” prop to change the color of our button.

We can see the Button component using the example below. We can select which platform our app is previewed in by clicking on the toggle in the bottom right, then click on “Tap to Play” to preview the app.

import React, { Component } from 'react';
import { Button, StyleSheet, View } from 'react-native';

export default class ButtonBasics extends Component {
  _onPressButton() {
    alert('You tapped the button!')
  }

  render() {
    return (
      <View style={styles.container}>
        <View style={styles.buttonContainer}>
          <Button
            onPress={this._onPressButton}
            title="Press Me"
          />
        </View>
        <View style={styles.buttonContainer}>
          <Button
            onPress={this._onPressButton}
            title="Press Me"
            color="#841584"
          />
        </View>
        <View style={styles.alternativeLayoutButtonContainer}>
          <Button
            onPress={this._onPressButton}
            title="This looks great!"
          />
          <Button
            onPress={this._onPressButton}
            title="OK!"
            color="#841584"
          />
        </View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
   flex: 1,
   justifyContent: 'center',
  },
  buttonContainer: {
    margin: 20
  },
  alternativeLayoutButtonContainer: {
    margin: 20,
    flexDirection: 'row',
    justifyContent: 'space-between'
  }
});

The result of above example is displayed below :


Touchables

In React Native, most “buttons” are actually implemented using Touchable components. Like Button, these components support an onPress prop. However, unlike Button, these components support custom styling – essentially a Touchable is a View that can be pressed.

Touchables have a variety of other props, like onPressIn and onPressOut, which give us more control over the behavior of the button. We can use these props to run custom animations.


Kinds of Touchable

Although we can run custom animations, most of the time, we use one of 2 built-in animations: a fade in opacity, or a change of color. There are preconfigured touchable components for each of these: TouchableOpacity and TouchableHighlight.

Which “Touchable” component we use will depend on what kind of feedback we want to provide:

  • Generally, we can use TouchableHighlight anywhere we would use a button or link on web. The view’s background will be darkened when the user presses down on the button.
  • We may consider using TouchableNativeFeedback on Android to display ink surface reaction ripples that respond to the user’s touch.
  • TouchableOpacity can be used to provide feedback by reducing the opacity of the button, allowing the background to be seen through while the user is pressing down.
  • If we need to handle a tap gesture but we don’t want any feedback to be displayed, use TouchableWithoutFeedback.

In some cases, we may want to detect when a user presses and holds a view for a set amount of time. These long presses can be handled by passing a function to the onLongPress props of any of the “Touchable” components.


Example

Let’s see all of these in action:

import React, { Component } from 'react';
import { Platform, StyleSheet, Text, TouchableHighlight, TouchableOpacity, TouchableNativeFeedback, TouchableWithoutFeedback, View } from 'react-native';

export default class Touchables extends Component {
  _onPressButton() {
    alert('You tapped the button!')
  }

  _onLongPressButton() {
    alert('You long-pressed the button!')
  }

  render() {
    return (
      <View style={styles.container}>
        <TouchableHighlight onPress={this._onPressButton} underlayColor="white">
          <View style={styles.button}>
            <Text style={styles.buttonText}>TouchableHighlight</Text>
          </View>
        </TouchableHighlight>
        <TouchableOpacity onPress={this._onPressButton}>
          <View style={styles.button}>
            <Text style={styles.buttonText}>TouchableOpacity</Text>
          </View>
        </TouchableOpacity>
        <TouchableNativeFeedback
            onPress={this._onPressButton}
            background={Platform.OS === 'android' ? TouchableNativeFeedback.SelectableBackground() : ''}>
          <View style={styles.button}>
            <Text style={styles.buttonText}>TouchableNativeFeedback {Platform.OS !== 'android' ? '(Android only)' : ''}</Text>
          </View>
        </TouchableNativeFeedback>
        <TouchableWithoutFeedback
            onPress={this._onPressButton}
            >
          <View style={styles.button}>
            <Text style={styles.buttonText}>TouchableWithoutFeedback</Text>
          </View>
        </TouchableWithoutFeedback>
        <TouchableHighlight onPress={this._onPressButton} onLongPress={this._onLongPressButton} underlayColor="white">
          <View style={styles.button}>
            <Text style={styles.buttonText}>Touchable with Long Press</Text>
          </View>
        </TouchableHighlight>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    paddingTop: 60,
    alignItems: 'center'
  },
  button: {
    marginBottom: 30,
    width: 260,
    alignItems: 'center',
    backgroundColor: '#2196F3'
  },
  buttonText: {
    textAlign: 'center',
    padding: 20,
    color: 'white'
  }
});

The result of above example is displayed below :


Scrolling and swiping

Gestures commonly used on devices with touchable screens include swipes and pans. These allow the user to scroll through a list of items, or swipe through pages of content. 

That’s all about in this article.


Conclusion

In this article, We understood about how to use Touchable Components in React Native.

Thanks for reading ! I hope you enjoyed and learned about the Touchable Components Concepts in React Native. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolmonkTechie as below link :

You can also follow official website and tutorials of React Native as below links :

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING!!???

Exit mobile version