Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
React: Cross-Platform Application Development with React Native

You're reading from   React: Cross-Platform Application Development with React Native Build 4 real-world apps with React Native

Arrow left icon
Product type Paperback
Published in Mar 2018
Publisher Packt
ISBN-13 9781789136081
Length 182 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Author (1):
Arrow left icon
Emilio Rodriguez Martinez Emilio Rodriguez Martinez
Author Profile Icon Emilio Rodriguez Martinez
Emilio Rodriguez Martinez
Arrow right icon
View More author details
Toc

ConfirmationModal

Our last component is a modal view, which will be opened once the user has pressed on the SET PICKUP LOCATION button on the location pin. We will display the modal and a custom activity indicator, which will use a complex animation setup to continuously rotate in its position:

/** * src/components/ConfirmationModal.js ***/

import React from 'react';
import {
Modal,
  View,
  Text,
  Animated,
  Easing,
  TouchableOpacity,
  StyleSheet,
} from 'react-native';

export default class ConfirmationModal extends React.Component {
  componentWillMount() {
    this._animatedValue = new Animated.Value(0);
  }

cycleAnimation() {
    Animated.sequence([
      Animated.timing(this._animatedValue, {
        toValue: 100,
        duration: 1000,
        easing: Easing.linear,
      }),
      Animated.timing(this._animatedValue, {
        toValue: 0,
        duration: 0,
      }),
    ]).start(() => {
      this.cycleAnimation();
    });
  }

componentDidMount() {
    this.cycleAnimation();
  }

  render() {
const interpolatedRotateAnimation = this._animatedValue.interpolate({
      inputRange: [0, 100],
      outputRange: ['0deg', '360deg'],
    });

    return (
<Modal
        animationType={'fade'}
        visible={this.props.visible}
        transparent={true}
      >
        <View style={styles.overlay}>
          <View style={styles.container}>
            <Text style={styles.title}>Contacting nearest car...</Text>
<Animated.Image
              style={[
                styles.spinner,
                { transform: [{ rotate: interpolatedRotateAnimation }] },
              ]}
              source={require('../../img/loading.png')}
            />
            <TouchableOpacity
              style={styles.closeButton}
              onPress={this.props.onClose}
            >
              <Text style={styles.closeButtonText}>X</Text>
            </TouchableOpacity>
          </View>
        </View>
      </Modal>
    );
  }
}

const styles = StyleSheet.create({
  overlay: {
    flex: 1,
    backgroundColor: '#0006',
    justifyContent: 'center',
  },
  container: {
    backgroundColor: 'white',
    alignSelf: 'center',
    padding: 20,
    borderColor: '#ccc',
    borderWidth: 1,
  },
  title: {
    textAlign: 'right',
    fontFamily: 'Blair ITC',
    paddingTop: 5,
    fontSize: 12,
  },
  spinner: {
    resizeMode: 'contain',
    height: 50,
    width: 50,
    margin: 50,
    alignSelf: 'center',
  },
  closeButton: {
    backgroundColor: '#333',
    width: 40,
    height: 40,
    borderRadius: 20,
    justifyContent: 'center',
    alignSelf: 'center',
  },
  closeButtonText: {
    color: 'white',
    alignSelf: 'center',
    fontSize: 20,
  },
});

For this component, we are using the <Modal /> component available in React Native to take advantage of its fade animation and visibility capabilities. The property this.props.visible will drive the visibility of this component as it is the parent who is aware of the pickup request from the user.

Let's focus again on animations as we want to do a more complex setup for the spinner showing activity. We want to display an endless rotating animation, so we need to systematically call our start() animation method. In order to achieve this, we created a cycleAnimation() method, which is called on the component mount (to get the animation started) and from the Animated.timing returned object as it is passed as a callback to be invoked every time the animation ends.

We are also using Animated.sequence to concatenate two animations:

  • Moving from 0 degrees to 360 (in one second using a linear easing)
  • Moving from 360 degrees to 0 (in 0 seconds)

This is required to repeat the first animation over at the end of each cycle.

Finally, we defined a variable named interpolatedRotateAnimation to store the interpolation from 0 degrees to 360, so it can be passed to the transform/rotate style defining what are going to be the available rotation values when animating our Animated.Image.

As an experiment, we can try and change loading.png with an alternative image and see how it gets animated. This can be easily achieved by replacing the source property in our <Animated.Image /> component:

...            

            <Animated.Image
              style={[
                styles.spinner,
                { transform: [{ rotate: interpolatedRotateAnimation }] },
              ]}
source={require('../../img/spinner.png')}
            />

...
lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €18.99/month. Cancel anytime