React Native Travel Article App UI Clone #5 : Animated Delimiter 
Tags: react, reactnative, reactnativetemplat, reactnativetravel
Published: 2019-11-09 01:54:18

---
title: React Native Travel Article App UI Clone #5 : Animated Delimiter 
published: true
date: 2019-11-08 07:18:50 UTC
tags: React,React native,React native templat,React native Travel 
canonical_url: https://kriss.io/react-native-travel-article-app-ui-clone-5-animated-delimiter-dots/
cover_image: https://kriss.io/wp-content/uploads/2019/11/React-Native-Travel-Article-App-UI-1-2.png
series: React Native Travel Article App UI
---

This tutorial is the fifth part of our React Native Travel Article App UI clone series. In the [previous part](https://kriss.io/react-native-travel-article-app-ui-clone-4-recommendation-section/), we successfully implemented the Recommendation Section on our List Screen. This tutorial is the continuation of the same tutorial from where we left off in the last part. So, it is recommended to go through the previous parts in order to get the knowledge and insight into the overall project.

In case of wanting to learn from the beginning, all the parts for this tutorial series are available below:


    - [React Native Travel Article App UI Clone #1: Getting Started](https://kriss.io/react-native-travel-article-app-ui-clone-1-getting-started/)
    - [Building React Native Travel Article App UI Clone #2: Destinations Section](https://kriss.io/react-native-travel-article-app-ui-clone-2-destinations-section/)
    - [React Native Travel Article App UI Clone #3: Destinations Info Section](https://kriss.io/react-native-travel-article-app-ui-clone-3-destination-info-section/)
    - [React Native Travel Article App UI Clone #4: Recommendation Section](https://kriss.io/react-native-travel-article-app-ui-clone-4-recommendation-section/)

The motivation for this tutorial series came from the [React Native App Templates](https://www.instamobile.io/) that consists of a wide variety of beautiful templates written in React Native and powered by universal features and design. The templates enable us to implement our own apps and even help us get started with our own startups. And, this fifth part is also the continuation of the same coding implementations and designs from the Youtube video tutorial by [React UI Kit](https://www.youtube.com/watch?v=zJ9QETiwdfo&list=PLNRPou200YIeu4UllJkv8-Ca19Ld_eOay&index=7) for the Travel Article App UI clone. The video tutorial delivers the overall tutorial using fast coding which may be difficult to grasp for any developer especially the beginners. Hence, this article tutorial provides a step by step implementation which will be easier to understand and implement. So, the learners can relax and take their time to implement the UI.

### Overview

In this fifth part of this tutorial series, we are going to implement the Animated Delimeter dots of the Destinations section. The idea is to make the delimiter dots active in the animated fashion while scrolling the Destination section cards.  After we complete this, we are going to store our color and size style properties in a different file. Then, we are going to use the style properties from that file to style the components in our List Screen. This will make our code clean and organized for better understanding.

_So, let us begin!!_  

 

## Making Some Configuration in `FlatList` of Destinations section

Here, we are going to add an additional prop to the FlatList component of the Destinations section. The prop we are going to add is `decelerationRate`. This `decelerationRate` prop is a floating-point number that determines how quickly the scroll view decelerates after the user lifts their finger. Now, we are going to add this prop to our `FlatList` component as shown in the code snippet below:

```javascript
 <View style={[ styles.flex, styles.column, styles.destinations]}>
              <FlatList 
                horizontal
                pagingEnabled
                scrollEnabled
                showsHorizontalScrollIndicator = {false}
                scrollEventThrottle = {16}
                snapToAlignment = "center"
                decelerationRate={0}
                // style={{ overflow : 'visible' }} //In IOS platform
                data = {destinations}
                keyExtractor = {(item, index)=> `${item.id}`}
                renderItem = {({item}) => this.renderDestination(item)}
              />
              {this.renderDots()}
            </View>
```

 

## Adding Animation to Delimiter Dots

In this step, we are going to add the Animation to our Delimiter Dots in our Destinations section. For that, we need to import the Animated component from the react-native package as shown in the code snippet below:

```javascript
import { 
  StyleSheet, 
  Platform, 
  Text, 
  View, 
  ScrollView,
  Dimensions, 
  ImageBackground, 
  Image, 
  FlatList, 
  TouchableOpacity, 
  Animated
} from 'react-native';
```

Now, we need to define a variable called `scrollX` that is initialized to `Animated` value. This variable will store our animation value for horizontal animation. In order to do this, we need to use the code from the following code snippet:

```javascript
export default class List extends React.Component {
    scrollX = new Animated.Value(0);
```

Here, the `Animated.Value` configuration enables us to bind to style properties or other props and can be interpolated as well. Now, we need to configure this `scrollX` value into the `onScroll` event of the `FlatList` component of `renderDestinations()` function as shown in the code snippet below:

```javascript
     <FlatList 
                horizontal
                pagingEnabled
                scrollEnabled
                showsHorizontalScrollIndicator = {false}
                scrollEventThrottle = {16}
                snapToAlignment = "center"
                decelerationRate={0}
                // style={{ overflow : 'visible' }} //In IOS platform
                onScroll={Animated.event([{ nativeEvent: { contentOffset: { x: this.scrollX }} }])}
                data = {destinations}
                keyExtractor = {(item, index)=> `${item.id}`}
                renderItem = {({item}) => this.renderDestination(item)}
              />
```

Here, we have used the `event` function of the `Animated` component which takes the `nativeEvent` as a parameter. Then, we have defined the `contentOffset` value according to the `scrollX` variable inside the `nativeEvent` config.  

### **Configuring Animation in Delimiter dots in accordance with the `FlatList` scrolling**

Here, we are going to add animation to the Delimiter dots which will depend on the onScroll event of the FlatList. For that, we need to first initialize the dot position using the `divide` function of the `Animated` component. The `divide` function creates a new `Animated` value composed by dividing the first Animated value by the second Animated value. And, its use is shown in the code snippet below:

```javascript
    const dotPosition = Animated.divide(this.scrollX, width);
```

  Now, we are going to make some configuration in the `renderDots()` function in order to animation properties to the Delimiter dots. For that, we need to use the code from the code snippet below:

```javascript
renderDots() {
    const dotPosition = Animated.divide(this.scrollX, width);
    return (
      <View style={[
        styles.flex, styles.row,
        { justifyContent: 'center', alignItems: 'center', marginTop: 10 }
      ]}>
        {destinations.map((item, index) => {
          const borderWidth = dotPosition.interpolate({
            inputRange: [index -1, index, index + 1],
            outputRange: [0, 2.5, 0],
            extrapolate: 'clamp'
          });
          return (
            <Animated.View
              key={`step-${item.id}`}
              style={[styles.dots, styles.activeDot, { borderWidth: borderWidth } ]}
            />
          )
        })}

      </View>
    )
  }
```

Here, we have defined a constant called `borderWidth`  which is initialized to the `interpolate()` function of the `dotPosition` constant `initlized` to `Animated.divide`. The `interpolate()` function takes `inputRange`, `outputRange` and `extrapolate` as parameter values.  The `interpolate()` function permits input ranges to map to different output ranges. Then, we have also added `Animated` component to our `View` component with `borderWidth` style property. Hence, we will get the following result in our emulator screen:

![](https://kriss.io/wp-content/uploads/2019/11/active-dot-scrolling.gif)

As we can see, we have successfully added beautiful animation to the Delimiter dots as we scroll the Destination section card in the Destination section. The animation is very smooth and works well with the scrolling transition.  

 

## Configuring Style properties

Here, we are going to configure the style properties from a separate file. Then, we will style our List Screen components according to the style properties in that file.  

### Storing Style Properties in Different File

In this step, we are going to store our size and color properties used very commonly on the List screen to a different file called ‘theme.js’. This will make things easier for us to assign styles to different components. Now, we need to create a file called ‘theme.js’ in our main project folder as shown in the code snippet below:

![](https://kriss.io/wp-content/uploads/2019/11/Screenshot-2019-11-05-145407.png)

As we can see, we have got the ‘theme.js’ file. Now, in the theme.js file we need to define our colors and sizes properties as shown in the code snippet below:

```css
  const colors = {
    black: '#000',
    white: '#FFF',
    gray: '#DCE0E9',
    caption: '#BCCCD4',
    active: '#007BFA',
  };
  
  const sizes = {
    base: 16,
    font: 14,
    padding: 36,
    margin: 36,
    title: 24,
    radius: 12,
  };
  
  export {
    colors,
    sizes,
  };
```

Here, we have defined the color and size style properties in the `colors` and `sizes` constant variables that are then exported.

 

### Integrating Color and Size style properties based on theme.js file


Since we have defined some common style properties in the theme.js file, here we are going to import the styles from theme.js file and integrate them into our component inline styles as well as the styles in the `StyleSheet` component. But first, we need to import the theme.js file into our List.js file as shown in the code snippet below:

```javascript
import * as theme from '../theme';
```

Now, we are going to change the color and size style properties in accordance with the pre-defined styles from the theme.js file.  

#### **Changing color style properties in accordance with theme.js**

Here, we are going to change the color style properties in the List.js file with the `colors` variable from the theme.js file. All the changes made to the style properties in the `StyleSheet` component is provided in the code snippet below:

```css
    header: {
        backgroundColor: theme.colors.white,
        paddingHorizontal: 36,
        paddingTop: 48,
        paddingBottom: 24,
        justifyContent: 'space-between',
        alignItems: 'center',
    },
    destinationInfo : {
      position : 'absolute',
      borderRadius : 12,
      paddingHorizontal : 36,
      paddingVertical : 16,
      bottom : 20,                       //In iOS platform, bottom : -36
      left : 36,
      right : 36,
      backgroundColor : theme.colors.white,
    },
    recommendation: {
      width: (width - (36 * 2)) / 2,
      marginHorizontal: 8,
      backgroundColor: theme.colors.white,
      overflow: 'hidden',
      borderRadius: 12,
      marginVertical: 36 * 0.5,
    },
    recommendationTemp: {
      fontSize: 14 * 1.25,
      color: theme.colors.white
    },
    rating: {
      fontSize: 28,
      color: theme.colors.white,
      fontWeight: 'bold'
    },
    shadow : {
      shadowColor: theme.colors.black,
      shadowOffset: {
        width: 0,
        height: 6,
      },
      shadowOpacity: 0.05,
      shadowRadius: 10,
      elevation: 5,
    },
   dots: {
      width: 10,
      height: 10,
      borderWidth: 2.5,
      borderRadius: 5,
      marginHorizontal: 6,
      backgroundColor: theme.colors.gray,
      borderColor: 'transparent',
    },
    activeDot: {
      width: 12.5,
      height: 12.5,
      borderRadius: 6.25,
      borderColor: theme.colors.active,
    }
```

Now, we have some inline styles as well bound to the components in the different templating methods. We need to change them in accordance with `colors` variable as well. All overall code with changes is provided in the code snippets below:

In the `header` config of the `navigationOptions` object:

```javascript
 <Text style={{color : theme.colors.caption}}>Search for place</Text>
```

For the `renderDestination()` function:

```javascript
renderDestination(item){
      return(
        <ImageBackground
          style={[styles.flex, styles.destination, styles.shadow]}
          imageStyle = {{borderRadius : 12}}
          source= {{uri : item.preview}}
        >
          <View style={[styles.row, {justifyContent: 'space-between'}]}>
            <View style={{flex : 0}}>
              <Image source={{uri: item.user.avatar}} style={styles.avatar}/>
            </View>
            <View style={[styles.column, {flex : 2, paddingHorizontal : 18}]}>
              <Text style={{color : theme.colors.white, fontWeight : 'bold'}}>{item.user.name}</Text>
              <Text style={{color : theme.colors.white}}>{item.location}</Text>
            </View>
            <View style={{flex : 0, justifyContent : 'center', alignItems : 'flex-end'}}>
              <Text style={styles.rating}>{item.rating}</Text>
            </View>
          </View>
          <View style={[styles.column, styles.destinationInfo, styles.shadow]}>
            <Text style={{ fontSize: 24, fontWeight: '500', paddingBottom: 8, }}>
              {item.title}
            </Text>
            <View style={[ styles.row, { justifyContent: 'space-between', alignItems: 'flex-end'}]}>
              <Text style={{ color : theme.colors.caption}}>
                {item.description.split('').slice(0, 50)}...
              </Text>
            </View>
          </View>

        </ImageBackground>
      )
    }
```

In the `renderRecommended()` function:

```javascript
  <TouchableOpacity activeOpacity={0.5}>
     <Text style={{ color: theme.colors.caption }}>More</Text>
 </TouchableOpacity>
```

For the `renderRecommendations()` function:

```javascript
 <View style={[styles.flex, styles.column, styles.shadow, { justifyContent: 'space-evenly', padding: 36 / 2 }]}>
              <Text style={{ fontSize: 16 * 1.25, fontWeight: '500', paddingBottom: 36 / 4.5, }}>{item.title}</Text>
              <Text style={{ color: theme.colors.caption}}>{item.location}</Text>
              <View style={[
                styles.row,
                { alignItems: 'center', justifyContent: 'space-between', marginTop: 36 }
              ]}>
                <Text style={{ color: theme.colors.active }}>{item.rating}</Text>
              </View>
            </View>
```

 

#### Changing size properties in accordance with theme.js


Here, we are going to change the size style properties in the List.js file with the `sizes` variable from the theme.js file. All the changes made to the style properties in the `StyleSheet` component is provided in the code snippet below:

```css
    header: {
      backgroundColor: theme.colors.white,
      paddingHorizontal: theme.sizes.padding,
      paddingTop: theme.sizes.padding * 1.33,
      paddingBottom: theme.sizes.padding * 0.66,
      justifyContent: 'space-between',
      alignItems: 'center',
    },
    destinations : {
      flex: 2,
      justifyContent: 'space-between',
      paddingBottom: 30,
    },
    destination : {
      width : width - (theme.sizes.padding * 2),
      height : width * 0.66,
      marginHorizontal : theme.sizes.margin,
      paddingHorizontal : theme.sizes.padding,
      paddingVertical : 20,
      borderRadius : theme.sizes.radius
    },
    destinationInfo : {
      position : 'absolute',
      borderRadius : theme.sizes.radius,
      paddingHorizontal : theme.sizes.padding,
      paddingVertical : 16,
      bottom : 20,                       //In iOS platform, bottom : -36
      left : theme.sizes.padding,
      right : theme.sizes.padding,
      backgroundColor : theme.colors.white,
    },
    recommendedHeader: {
      justifyContent: 'space-between',
      alignItems: 'flex-end',
      paddingHorizontal: theme.sizes.padding,
    },
    recommendation: {
      width: (width - (theme.sizes.padding * 2)) / 2,
      marginHorizontal: 8,
      backgroundColor: theme.colors.white,
      overflow: 'hidden',
      borderRadius: theme.sizes.radius,
      marginVertical: theme.sizes.margin * 0.5,
    },
    recommendationHeader: {
      overflow: 'hidden',
      borderTopRightRadius: theme.sizes.radius,
      borderTopLeftRadius: theme.sizes.radius,
    },
    recommendationOptions: {
      alignItems: 'center',
      justifyContent: 'space-between',
      padding: theme.sizes.padding / 2,
      position: 'absolute',
      top: 0,
      left: 0,
      right: 0,
    },
    recommendationTemp: {
      fontSize: 14 * 1.25,
      color: theme.colors.white
    },
    recommendationImage: {
      width: (width - (theme.sizes.padding* 2)) / 2,
      height: (width - (theme.sizes.padding * 2)) / 2,
    },
    avatar :{
      width: theme.sizes.padding,
      height : theme.sizes.padding,
      borderRadius : theme.sizes.padding / 2
    },
    rating: {
      fontSize: theme.sizes.font * 2,
      color: theme.colors.white,
      fontWeight: 'bold'
    },
```

Now, we have some inline styles as well bound to the components in the different templating methods. We need to change them in accordance with `sizes` variable as well. All overall code with changes is provided in the code snippets below:

In the `header` config of the `navigationOptions` object:

```javascript
<Text style={{fontSize : theme.sizes.font \* 2}}>Destination</Text>
```

For the `renderDots()` function:

```javascript
       <View 
          style={[ 
                  styles.flex, 
                  styles.row, 
                  {justifyContent: 'center',alignItems:'center', marginTop : Platform.OS === 'ios' ? theme.sizes.padding * 2 : 48}
                ]}
         > 
          .................
```

In the `renderDestinations()` function:

```javascript
        <ImageBackground
          style={[styles.flex, styles.destination, styles.shadow]}
          imageStyle = {{borderRadius : theme.sizes.radius}}
          source= {{uri : item.preview}}
        >
          <View style={[styles.row, {justifyContent: 'space-between'}]}>
            <View style={{flex : 0}}>
              <Image source={{uri: item.user.avatar}} style={styles.avatar}/>
            </View>
            <View style={[styles.column, {flex : 2, paddingHorizontal : theme.sizes.padding / 2}]}>
              <Text style={{color : theme.colors.white, fontWeight : 'bold'}}>{item.user.name}</Text>
              <Text style={{color : theme.colors.white}}>{item.location}</Text>
            </View>
            <View style={{flex : 0, justifyContent : 'center', alignItems : 'flex-end'}}>
              <Text style={styles.rating}>{item.rating}</Text>
            </View>
          </View>
          <View style={[styles.column, styles.destinationInfo, styles.shadow]}>
            <Text style={{ fontSize: theme.sizes.title, fontWeight: '500', paddingBottom: 8, }}>
              {item.title}
            </Text>
            <View style={[ styles.row, { justifyContent: 'space-between', alignItems: 'flex-end'}]}>
              <Text style={{ color : theme.colors.caption}}>
                {item.description.split('').slice(0, 50)}...
              </Text>
            </View>
          </View>

        </ImageBackground>
```

For `renderRecommended()` function:

```javascript
<Text style={{ fontSize: theme.sizes.font \* 1.4 }}>Recommended</Text>
```

In `renderRecommendation()` function:

```javascript
                 <View 
            style={[styles.flex, styles.column, styles.recommendation, styles.shadow,
                    index === 0 ? { marginLeft: theme.sizes.margin } : null,
                    isLastItem ? { marginRight: theme.sizes.margin / 2 } : null,
                   ]}
           >
            <View style={[styles.flex, styles.recommendationHeader]}>
              <Image style={[styles.recommendationImage]} source={{ uri: item.preview }} />
              <View style={[ styles.flex, styles.row, styles.recommendationOptions ]}>
                <Text style={styles.recommendationTemp}>
                  {item.temperature}℃
                </Text>
              </View>
            </View>
            <View style={[styles.flex, styles.column, styles.shadow, { justifyContent: 'space-evenly', padding: theme.sizes.padding / 2 }]}>
              <Text style={{ fontSize: theme.sizes.font * 1.25, fontWeight: '500', paddingBottom: theme.sizes.padding / 4.5, }}>{item.title}</Text>
              <Text style={{ color: theme.colors.caption}}>{item.location}</Text>
              <View style={[
                styles.row,
                { alignItems: 'center', justifyContent: 'space-between', marginTop: theme.sizes.margin }
              ]}>
                <Text style={{ color: theme.colors.active }}>{item.rating}</Text>
              </View>
            </View>
          </View>
```

Hence, after everything is organized, we will get the same result as before which is shown in the following emulator simulation:

![](https://kriss.io/wp-content/uploads/2019/11/scrolling-and-active-dots-final.gif)

As we can see, the result is the same as before with all the codes organized. Now, we will be able to configure style properties easily in the upcoming parts of this tutorial series. With this, we have come to the end of this part of the tutorial series.

Finally, we have successfully implemented the Animated Delimiter dots in the Destinations section of our List screen.

 

## **Conclusion**



This tutorial is the fifth part of the React Native Travel Article App UI clone tutorial series. In this part, we continued from where we left off in the fourth part of this tutorial series. In this part of the tutorial, we got stepwise guidance on how to add beautiful active style animation to the Delimiter dots of the Destinations section. Hence, we made the active animation of Delimeter dots in accordance with the scrolling of the Destination section cards. Then, we also organized our inline styles and styles in the `StyleSheet` component to make code standard and clear. Hence, we can now style our components more easily in the upcoming parts of this tutorial series.



In the next part of this tutorial series, we are going to add the icons to our List screen as well as the rating stars to our Recommendation Info cards.

 

The post [React Native Travel Article App UI Clone #5 : Animated Delimiter Dots](https://kriss.io/react-native-travel-article-app-ui-clone-5-animated-delimiter-dots/) appeared first on [Kriss](https://kriss.io).