DEV Community

Cover image for React Native Travel Article App UI Clone #2 : Destinations Section
kris
kris

Posted on • Originally published at kriss.io on

React Native Travel Article App UI Clone #2 : Destinations Section

This tutorial is the second part of our React Native Travel Article App UI clone series. In the previous part, we successfully set up the overall project structure and established the base template with different UI sections for our Article 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 part in order to establish the basis and get insight into the overall project.

As mentioned in the previous part, the motivation to implement this UI clone series came from the React Native Universal Listings App Template that accommodates a wide variety of use cases, powered by universal features and design which allows us to implement our own apps to list anything that belongs in categories and can be added on a map. And, this second part is also the continuation of coding implementations and designs from the Youtube video tutorial by React UI Kit for the Travel Article App clone. The video tutorial provides overall guidance using fast coding which may be difficult to grasp for any developer especially the beginners. This written tutorial provides the step by step implementation which will be easier to understand and implement.

Overview

In this second part of this tutorial series, we are going to implement a portion of the Destinations section which we sectioned out in our previous tutorial part. The idea is to start by implementing the Destination section with a scrolling transition. Then, we will define mock destinations data which we will later integrate into the Destinations section. Lastly, we will style and configure the contents in the Destination section in order for it to look similar to the actual app.

So, let us begin!!

Implementing Destination Section

For starters, we are going to implement a simple Destination section template in the renderDestinations() method. For that, we need to use the code from the following code snippet:

renderDestinations(){
        return(
            <View style={[styles.flex, styles.column]}>
              <ScrollView horizontal>
                <Text>Destination 1</Text>
                <Text>Destination 2</Text>
                <Text>Destination 3</Text>
              </ScrollView>
            </View>
        )
    }

Here, we have included a ScrollView component that wraps three Text components. The ScrollView component allows us to integrate the scroll feature in the app. Since there is a prop horizontal included in the ScrollView component, we will be able to scroll horizontally.

Hence, we will get the following result in our emulator screen:

As we can see, we have got the Destinations section with three Text components. But this screen is not scrollable as there is no room for scrolling.

Now, we are going to style and configure this template in order to make it scrollable.

Adding Dimensions

Here, we are going to add the Dimensions component. This component allows us to take the full width and height of the app screen. For that, we need to use the code from the following code snippet:

import { StyleSheet, Text, View, ScrollView, Dimensions } from 'react-native'; 
const {height, width} = Dimensions.get('screen');

Here, we have imported the Dimensions component from the react-native package. Then, we have defined the height and width constants by using get() function of Dimensions module.

Making Destinations Section Scrollable

Now, we are going to make the Destinations section scrollable to the right. For that, we need to make use of Dimensions properties and different styles in our renderDestionations() method template. The coding implementation to make the Destinations section scrollable is provided in the code snippet below:

renderDestinations(){
        return(
            <View style={[styles.flex, styles.column]}>
              <ScrollView horizontal>
                <View style={[styles.flex, styles.destination]}>
                  <Text>Destination 1</Text>
                </View>
                <View style={[styles.flex, styles.destination]}>
                  <Text>Destination 1</Text>
                </View>
                <View style={[styles.flex, styles.destination]}>
                  <Text>Destination 1</Text>
                </View>
              </ScrollView>
            </View>
        )
    }

Here, we have included three View components inside the ScrollView component. Each View component wraps the Text component. There are also some styles bound to them. The required styles are provided in the code snippet below:

destination : {
      width : width - (36 * 2),
      borderRadius : 12,
      backgroundColor : 'pink'
    }

Hence, we will get the following result in our emulator screen:

As we can see, now we can scroll the View components with text in the Destinations section.

But what we want is to display only one View component at a time. And while scrolling it will immediately scroll to the next View component without consistent scrolling transition.

Configuring ScrollView

Here, we are going to make some configurations to ScrollView so that only one View component inside the ScrollView component displayed while scrolling motion. We also need to remove the horizontal scroll bar that appears at the bottom of the Destinations section. For that, we need to include different ScrollView configuration props to ScrollView. The overall coding implementation is provided in the code snippet below:

 <ScrollView 
                horizontal
                pagingEnabled
                scrollEnabled
                showsHorizontalScrollIndicator = {false}
                scrollEventThrottle = {16}
                snapToAlignment = "center"
              >
                <View style={[styles.flex, styles.destination]}>
                  <Text>Destination 1</Text>
                </View>
                <View style={[styles.flex, styles.destination]}>
                  <Text>Destination 1</Text>
                </View>
                <View style={[styles.flex, styles.destination]}>
                  <Text>Destination 1</Text>
                </View>
    </ScrollView>

As we can see, we have included five new props to the ScrollView. The function of all the props are listed below:

  • pagingEnabled : When its value is true, the scroll view stops on multiples of the scroll view’s size when scrolling. The default value is false.
  • scrollEnabled : When its value is false, the view cannot be scrolled via touch interaction. The default value is true.
  • showsHorizontalScrollIndicator: When its value is false, the horizontal scroll bar at the bottom does not show up.
  • scrollEventThrottle: This prop is used to controls how often the scroll event will be fired while scrolling (as a time interval in ms). A lower number corresponds to better accuracy for code that is tracking the scroll position.
  • snapToAlignment: This prop will define the relationship of the snapping to the scroll view.

There is also changes to some style properties which is provided below:

articles : {
    },
    destination : {
      width : width - (36 * 2),
      marginHorizontal : 36,
      padding : 36,
      borderRadius : 12,
      backgroundColor : 'pink'
    },

Adding style to the Recommendation section

Here, we are going to make a few style adjustments to the Recommendation section so that our Destinations section will appear better. For that, we need to use the code from the following code snippet:

renderRecommended(){
        return(
            <View style={[styles.flex, styles.column, styles.recommended]}>
                <Text>Recommended</Text>
            </View>
        )
    }

The required style is provided in the code snippet below:

recommended : {
      padding : 36
    }

Hence, we will get the following result in our emulator screen:

As we can see, when we scroll the Destinations section cards only one card is visible at a time. This makes the section more appealing and smooth. Now, we need to add some content to the Destinations section and style them so that it will look similar to the actual app.

Adding Mock data for Destinations section

Here, we are going to add the mock destinations data. For that, we need to define an array variable called destinations. Then, we need to define the array of objects inside the destinations array which will represent the data for each destination in the Destinations section. The required mock destinations array data is provided in the code snippet below:

const destinations = [
  {
    id: 1,
    user: {
      name: 'Lelia Chavez',
      avatar: 'https://randomuser.me/api/portraits/women/44.jpg',
    },
    saved: true,
    location: 'Santorini, Greece',
    temperature: 34,
    title: 'Santorini',
    description: 'Santorini is one of the Cyclades islands in the Aegean Sea. It was devastated by a volcanic eruption in the 16th century BC, forever shaping its rugged landscape. The whitewashed, cubiform houses of its 2 principal towns, Fira and Oia, cling to cliffs above an underwater caldera (crater). They overlook the sea, small islands to the west and beaches made up of black, red and white lava pebbles.',
    rating: 4.3,
    reviews: 3212,
    preview: 'https://images.unsplash.com/photo-1507501336603-6e31db2be093?auto=format&fit=crop&w=800&q=80',
    images: [
      'https://images.unsplash.com/photo-1507501336603-6e31db2be093?auto=format&fit=crop&w=800&q=80',
      'https://images.unsplash.com/photo-1507501336603-6e31db2be093?auto=format&fit=crop&w=800&q=80',
      'https://images.unsplash.com/photo-1507501336603-6e31db2be093?auto=format&fit=crop&w=800&q=80',
      'https://images.unsplash.com/photo-1507501336603-6e31db2be093?auto=format&fit=crop&w=800&q=80',
    ]
  },
  {
    id: 2,
    user: {
      name: 'Lelia Chavez',
      avatar: 'https://randomuser.me/api/portraits/women/44.jpg',
    },
    saved: false,
    location: 'Loutraki, Greece',
    temperature: 34,
    title: 'Loutraki',
    description: 'This attractive small town, 80 kilometers from Athens',
    rating: 4.6,
    reviews: 3212,
    preview: 'https://images.unsplash.com/photo-1458906931852-47d88574a008?auto=format&fit=crop&w=800&q=80',
    images: [
      'https://images.unsplash.com/photo-1458906931852-47d88574a008?auto=format&fit=crop&w=800&q=80',
      'https://images.unsplash.com/photo-1446903572544-8888a0e60687?auto=format&fit=crop&w=800&q=80',
    ]
  },
  {
    id: 3,
    user: {
      name: 'Lelia Chavez',
      avatar: 'https://randomuser.me/api/portraits/women/44.jpg',
    },
    saved: true,
    location: 'Santorini, Greece',
    temperature: 34,
    title: 'Santorini',
    description: 'Santorini - Description',
    rating: 3.2,
    reviews: 3212,
    preview: 'https://images.unsplash.com/photo-1507501336603-6e31db2be093?auto=format&fit=crop&w=800&q=80',
    images: [
      'https://images.unsplash.com/photo-1507501336603-6e31db2be093?auto=format&fit=crop&w=800&q=80',
      'https://images.unsplash.com/photo-1507501336603-6e31db2be093?auto=format&fit=crop&w=800&q=80',
      'https://images.unsplash.com/photo-1507501336603-6e31db2be093?auto=format&fit=crop&w=800&q=80',
      'https://images.unsplash.com/photo-1507501336603-6e31db2be093?auto=format&fit=crop&w=800&q=80',
    ]
  },
  {
    id: 4,
    user: {
      name: 'Lelia Chavez',
      avatar: 'https://randomuser.me/api/portraits/women/44.jpg',
    },
    location: 'Loutraki, Greece',
    temperature: 34,
    title: 'Loutraki',
    description: 'This attractive small town, 80 kilometers from Athens',
    rating: 5,
    reviews: 3212,
    preview: 'https://images.unsplash.com/photo-1458906931852-47d88574a008?auto=format&fit=crop&w=800&q=80',
    images: [
      'https://images.unsplash.com/photo-1458906931852-47d88574a008?auto=format&fit=crop&w=800&q=80',
      'https://images.unsplash.com/photo-1446903572544-8888a0e60687?auto=format&fit=crop&w=800&q=80',
    ]
  },
]

As we can see, the destinations array data contains four object items, each representing the single destination. Each data item contains an id, user info, location, temperature, title, description, rating, reviews, image preview and an additional set of images. Here, we are only going to include a few data from data items. But, other information from the data items will be useful in upcoming tutorials.

Separate function for each Destination cards

Here, we are going to define a separate function called renderDestination() that will return the template for each destination. The coding implementation of renderDestination() method is provided in the code snippet below:

renderDestination(item){
      return(
        <ImageBackground
          style={style.flex}
          source= {{uri : item.preview}}
        >
          <View style={[styles.flex, styles.row, styles.destination]}>
            <View>
              <Image source={{uri: item.user.avatar}} style={style.avatar}/>
            </View>
            <View style={[styles.flex, styles.column]}>
              <Text>{item.user.name}</Text>
              <Text>{item.location}</Text>
            </View>
            <View >
              <Text style={style.rating}>{item.rating}</Text>
            </View>
          </View>
        </ImageBackground>
      )
    }

Here, the renderDestination() function takes a single parameter called item. This item parameter will include each data object item from the destinations array that we defined earlier. Then, we have used the item data in order to implement a simple template. The template includes an ImageBackground component that wraps a View component. This ImageBackground component is used to set the background image on the app screen. The View component wraps the child View components with Text component for the destination information. There are some styles bound to them that are provided in the code snippet below:

avatar :{
      width: 36,
      height : 36,
      borderRadius : 18
}

Now, we need to configure the ScrollView in the renderDestinations() method as well. We need to call the renderDestionation() method in the renderDestinations() method by passing the item parameter. And, we are also going to change the ScrollView to FlatList component as well for better configuration.

Note that we need to remember to import the ImageBackground component from the react-native package.

Changing ScrollView to FlatList

Now, we are going to replace the ScrollView component in the renderDestinations() method with the FlatList component. The FlatList component can be configured with all the props from the ScrollView component as well as provide a better transition as a List view. The changes made to the renderDestinations() function is provided in the code snippet below:

renderDestinations(){
        return(
            <View style={[styles.flex, styles.column]}>
              <FlatList 
                horizontal
                pagingEnabled
                scrollEnabled
                showsHorizontalScrollIndicator = {false}
                scrollEventThrottle = {16}
                snapToAlignment = "center"
                data = {destinations}
                keyExtractor = {(item, index)=> `${item.id}`}
                renderItem = {({item}) => this.renderDestination(item)}
              />
            </View>
        )
    }

Here, we have completely replaced the ScrollView component with FlatList component. All the props integrated into ScrollView are included in the FlatList. The additional data prop takes in the destinations array data. The keyExtractor prop is used to identify each item in the list uniquely. And, the renderItem prop function returns the required template which in this case is calling the renderDestination() function with the item parameter.

Note that, we need to remember to import FlatList component from the react-native package.

Hence, we will get the following result in our emulator screen:

As we can see, we have got the Destination section card template on the app screen. But, this does not look appealing at all. So, we need to configure the destination card with additional components and styles to make it look like in the actual app.

Configuring Single Destination card

Here, we are going to configure the Destination card with different components and styles in order to make it look appealing as in the actual app. For that, we need to make some changes to the renderDestination() function. The changes made in the renderDestinations() function is provided in the code snippet below:

renderDestination(item){
      return(
        <ImageBackground
          style={[styles.flex, styles.destination]}
          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 : 'white', fontWeight : 'bold'}}>{item.user.name}</Text>
              <Text style={{color : 'white'}}>{item.location}</Text>
            </View>
            <View style={{flex : 0, justifyContent : 'center', alignItems : 'flex-end'}}>
              <Text style={styles.rating}>{item.rating}</Text>
            </View>
          </View>
        </ImageBackground>
      )
    }

The required styles are provided in the code snippet below:

 rating: {
      fontSize: 28,
      color: 'white',
      fontWeight: 'bold'
    },
    destination : {
      width : width - (36 * 2),
      marginHorizontal : 36,
      paddingHorizontal : 36,
      paddingVertical : 24,
      borderRadius : 12,
      backgroundColor : 'pink'
    },

Now, we also want to add an Avatar image to the header section of the List screen. For that, we need to use the code from the following code snippet:

   header: (
          <View style={[styles.row, styles.header]}>
            <View>
              <Text>Search for place</Text>
              <Text style={{fontSize : 24}}>Destination</Text>
            </View>
            <View>
              <Image style={styles.avatar} source={{ uri: 'https://randomuser.me/api/portraits/women/32.jpg'}} /> 
            </View>
          </View>
        )

Here, we have included an Image component with a source prop for the avatar image URL.

Hence, we will get the following result in our emulator screen:

As we can see, our destination cards in the Destinations sections look very attractive now. We have also got the Avatar image in the header. With this, we have come to the end of this part of the tutorial.

Finally, We have successfully implemented the scrolling cards transition of the Destinations section in the List screen of our React Native Travel Article UI clone app.

Conclusion

This tutorial is the second part of the React Native Travel Article App UI clone tutorial series. In this part, we continued from where we left off in the first part of this tutorial series. In this part of the tutorial, we got step by step guide on how to implement the horizontal scrolling transition in our Destinations section. Then, we also learned how to use FlatList with different prop configurations to make the scrolling transition of cards a lot better. Lastly, we added different elements to our destination cards with an Avatar image in the header section of the List screen as well.

In the next part of this tutorial series, we are going to implement the remaining portion of our Destinations section. This will include the Destination information card section and active scrolling dots.

So, Stay Tuned folks!!!

The post React Native Travel Article App UI Clone #2 : Destinations Section appeared first on Kriss.

Top comments (0)