DEV Community

Cover image for Camping Spots Finder App UI Clone with React Native #4 : Map Marker
absek
absek

Posted on • Originally published at kriss.io on

Camping Spots Finder App UI Clone with React Native #4 : Map Marker

This tutorial is the fourth and final part of our Camping Spots Finder App UI clone using React Native. In the previous part, we successfully implemented the Settings screen with various UI sections. This tutorial is the continuation of where we left off in the last part. So, it is suggested to go through the previous parts for the overall insight and development of this project.

As mentioned in the previous parts, this tutorial series was inspired by React native real estate template that enables us to build fully functional ready to deploy mobile applications that anyone can use to build their own React Native applications. And, this fourth part is also the continuation of coding implementations and designs from the Youtube video tutorial by React UI Kit for the Camping Spots Finder App clone.

In this final part of our tutorial series, we are going to implement the marker which will show the camping spots in the map view. But first, we have some incomplete business in our settings screen which is to include icons in the group buttons of Type section. Then, we will move to implement the Map marker. After that, we will show the marker on the map based on the header tabs.

So, let us begin!!

Adding Icons to Type section

In this step, we are going to add icons to the group buttons of the Type section in the settings screen. We have imported the required icon package beforehand in the earlier tutorials. Here we are going to use some of the packages which provided us with suitable icons. In the Type section, we just added the Text component containing the text in the group buttons. Now, we are going to add some icons above the Text component. In the first group button, we are going to add two icons from the Foundation and FontAwesome icons package wrapped by View component with an inline style. In the second and third group buttons, we are going to add single icons each using the Foundation icon package in second and FontAwesome in the third. For that, we need to use the code from the following code snippet:

         <View style={styles.section}>
            <View>
              <Text style={styles.title}>Type</Text>
            </View>
            <View style={styles.group}>
             <TouchableOpacity
                style={[styles.button, styles.first, type == 'all' ? styles.active : null]}
                onPress={() => this.setState({ type: 'all' })}
              >
                <View style={{ flexDirection: 'row', }}>
                  <Foundation name="mountains" size={24}  />
                  <FontAwesome name="truck" size={24} />
                </View>
                <Text style={[styles.buttonText, type == 'all' ? styles.activeText : null]}>All</Text>
              </TouchableOpacity>
              <TouchableOpacity
                style={[styles.button, type == 'tent' ? styles.active : null]}
                onPress={() => this.setState({ type: 'tent' })}
              >
                <Foundation name="mountains" size={24}  />
                <Text style={[styles.buttonText, type == 'tent' ? styles.activeText : null]}>Tenting</Text>
              </TouchableOpacity>
              <TouchableOpacity
                style={[styles.button, styles.last, type == 'rv' ? styles.active : null]}
                onPress={() => this.setState({ type: 'rv' })}
              >
                <FontAwesome name="truck" size={24} />
                <Text style={[styles.buttonText, type == 'rv' ? styles.activeText : null]}>RV Camping</Text>
              </TouchableOpacity>
             </View>
          </View>

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

As we can see, we have got the icons in the group buttons of the Type section. But these icons are not configured with active style. That is why they appear with the default black color. Now, we need to configure these icons with active style so that the button along with its icon changes color when selected.

Switching color based on active Type

Here, we are going to switch the color of icons on the basis of the active button. For that, we need to define a function that handles the active type of the button called activeType(). This activeType() function will take on a key parameter which will be set to selected type when called. This key is then assigned to the type state that we defined in the earlier tutorial. The implementation of the function is provided in the code snippet below:

const activeType = (key) => type === key;

Now, we need to configure the styles in the Type section template based on the activeType() function as shown in the code snippet below:

         <View style={styles.group}>
              <TouchableOpacity
                style={[styles.button, styles.first, activeType('all') ? styles.active : null]}
                onPress={() => this.setState({ type: 'all' })}
              >
                <View style={{ flexDirection: 'row', }}>
                  <Foundation name="mountains" size={24} color={activeType('all') ? '#FFF' : '#FF7657' } />
                  <FontAwesome name="truck" size={24} color={activeType('all') ? '#FFF' : '#FFBA5A' } />
                </View>
                <Text style={[styles.buttonText, activeType('all') ? styles.activeText : null]}>All</Text>
              </TouchableOpacity>
              <TouchableOpacity
                style={[styles.button, activeType('tent') ? styles.active : null]}
                onPress={() => this.setState({ type: 'tent' })}
              >
                <Foundation name="mountains" size={24} color={activeType('tent') ? '#FFF' : '#FF7657'} />
                <Text style={[styles.buttonText, activeType('tent') ? styles.activeText : null]}>Tenting</Text>
              </TouchableOpacity>
              <TouchableOpacity
                style={[styles.button, styles.last, activeType('rv') ? styles.active : null]}
                onPress={() => this.setState({ type: 'rv' })}
              >
                <FontAwesome name="truck" size={24} color={activeType('rv') ? '#FFF' : '#FFBA5A'}/>
                <Text style={[styles.buttonText, activeType('rv') ? styles.activeText : null]}>RV Camping</Text>
              </TouchableOpacity>
            </View>

Therefore, we can see that the icon components that we added have been configured with a color style based on activeType() function. Moreover, all the dynamic styles that will represent the active and inactive state of the button are configured based on activeType() button. This will switch the color of the icon as well as a button when they are active. Hence, we get the following result as shown in the emulator screenshot below:

As we can see, the button along with its icon in the Type section changes color when they are in the active state. Therefore, this completes the overall implementation of the settings screen in our Camping Spots Finder app UI clone.

Now, we are going to move on to our Campings screen again. In the Campings screen, we have already set the MapView component which displays the map based on assigned co-ordinates. Now, we are going to add some markers to the map in order to display the Camping spots on the map. So, let us move to the Campings screen now.

Implementing Map Marker

Now, we are going back to our Campings screen in order to implement the marker in our MapView component. Since we have two camping sites on the list section, we are going to put on two markers on the map which represents their locations. But first, we need to include some addition location coordinate data into our campings array that we defined in earlier tutorials. We are going to include the latitude and longitude value of our camping sites into each object of our campings array as shown in the code snippet below:

const campings = [
      {
        id: 1,
        type: 'rv',
        name: 'Camping Paradise',
        description: 'Popular spot for trekkers.',
        rating: 4.9,
        distance: 2.9,
        price: 'Free',
        image: 'https://images.unsplash.com/photo-1525811902-f2342640856e?fit=crop&w=900&h=600&q=130',
        latlng: {
          latitude: 37.79335,
          longitude: -122.4424,
        }
      },
      {
        id: 2,
        type: 'tent',
        name: 'Lake Florida',
        description: 'This is for all sunset lovers.',
        rating: 4.9,
        distance: 2.9,
        price: 'Free',
        image: 'https://images.unsplash.com/photo-1506535995048-638aa1b62b77?fit=crop&w=900&h=600&q=130',
        latlng: {
          latitude: 37.78865,
          longitude: -122.4324,
        }
      },
    ];

Importing Marker component

Now, we are going to import the Marker component provided by the react-native-maps package. The Marker component is a method provided by MapView component that we imported from the react-native-maps package. Now, we are going to import the Marker component as shown in the code snippet below:

import MapView from 'react-native-maps'; 
const { Marker } = MapView;

Now, we need to add this Marker component to the MapView component that we defined in earlier tutorials inside the renderMap() method.

Adding Marker

Here, we are going to add the Marker component to the map. For that, the MapView component needs to wrap the Marker component inside the renderMap() method. The Marker component takes the prop coordinate value which we will set to the location values we defined in the campings array. The overall implementation of Marker in the MapView is provided in the code snippet below:

renderMap(){
    return(
      <View style={styles.map}>
          <MapView
            style={{flex: 1, height : height * 0.5, width}} 
            initialRegion={{
              latitude: 37.78825,
              longitude: -122.4324,
              latitudeDelta: 0.0922,
              longitudeDelta: 0.0421,
            }}
          >
            {campings.map(marker => (
              <Marker
                key={`marker-${marker.id}`}
                coordinate={marker.latlng}
              />
            ))}
          </MapView>
      </View>
    )
}

Here, we use the map() method which we can apply to any array to iterate through all its items. We need to attach map() function to campings array which will iterate through all the items inside the campings array which in this case are two objects. Then, the map() function will return a Marker template with the coordinate value from the campings array object. The Marker component is assigned a key prop in order to identify each Marker component uniquely.

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

As we can see, there are two location marker icons on the map. These location markers represent the location of the two camping sites in our campings array.

Now, we are going to change the location marker icons based on the type of the camping site. Unique marker icons will represent the unique camping sites based on their type.

Changing Marker Icons

Here, we are going to change our location marker icons to unique icons based on the type of camping site on the map. For that, we need to import some addition icon packages to the already imported icons package. Therefore, the icon packages that we need to import are provided in the code snippet below:

import { FontAwesome , Foundation, Ionicons, SimpleLineIcons} from '@expo/vector-icons';

Here, we have included the Foundation Icon package which will we make use of while defining the marker icons according to the type. Now, in the renderMap() method, we are going to define a function called campingMarker() which will return the appropriate marker icon based on the type of camping site. There are two types of camping sites as of now namely ‘rv’ and ‘tent’. The ‘rv’ type is for the RV campings where we can camp with your RV. The ‘tent’ type is for the tent camping where we can build a tent and camp. The implementation of the campingMarker() function is provided in the code snippet below:

renderMap() {
    const campingMarker = ({type}) => (
      <View style={[styles.marker, styles[`${type}Marker`]]}>
        {type === 'rv' ?
          <FontAwesome name="truck" size={18} color="#FFF" />
          : <Foundation name="mountains" size={18} color="#FFF" />
        }
      </View>
    )

Here, the campingMarker() function takes a parameter called type which will represent the type of camping site. And based on the type value, it will return the appropriate marker icon. We can also see some styles bound to the View component inside the function. The required styles are provided in the code snippet below:

 marker: {
    width: 40,
    height: 40,
    borderRadius: 40,
    justifyContent: 'center',
    alignItems: 'center',
    borderWidth: 1,
    borderColor: '#FFF',
  },
  rvMarker: {
    backgroundColor: '#FFBA5A',
  },
  tentMarker: {
    backgroundColor: '#FF7657',
  },

Adding the icon to Marker

Now, we need to call the campingMarker() function inside of the Marker component as shown in the code snippet below:

return(
      <View style={styles.map}>
          <MapView
            style={{flex: 1, height : height * 0.5, width}} 
            showsMyLocationButton
            initialRegion={{
              latitude: 37.78825,
              longitude: -122.4324,
              latitudeDelta: 0.0922,
              longitudeDelta: 0.0421,
            }}
          >
            {this.state.campings.map(marker => (
              <Marker
                key={`marker-${marker.id}`}
                coordinate={marker.latlng}
              >
                {campingMarker(marker)}
              </Marker>
            ))}
          </MapView>
      </View>
    )

Here, we have called the campingMarker() method inside the Marker component with a parameter called marker assigned to it. The marker parameter contains a single object in our campings array which represents the whole data of the camping spot.

Note that, we have also included the showsMyLocationButton prop in the MapView component. If showsMyLocationButton is false then, it hides the button to move the map to the current user’s location.

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

As we can see, we have got the location marker on the screen with unique icons for both ‘rv’ type and ‘tent’ type. Hence, we have successfully completed the implementation of unique Map Marker on the map of our Camping Spot Finder app UI clone.

But wait, it’s not over yet. We need to implement one more thing. That is to change the location markers on the map based on the header tabs that we set up in the first tutorial.

Showing Markers based on header tabs

We might have remembered that we implemented the header tabs section with tab buttons in our first part of this tutorial series. There were three header tab buttons called ‘All Spots’, ‘Tenting’ and ‘RV Camping’ which we can see above in the screenshots of campings screen as well. Now, we need to show those map markers based on these 3 tab buttons. The result should be:

  • ‘All Spots’ shows all the camping spots.
  • ‘Tenting’ shows all the camping spots with type ‘tent’.
  • ‘RV Campings’ shows all the camping spots with type ‘rv’.

For that, we need to define a new state called campings which will be set to the campings array that we defined earlier containing the camping spot object data. The state is to be defined as shown in the code snippet below:

state = {
    active : 'all',
    campings : campings
  }

Now, we need to include the campings array that from the state not from the original variable in the map() function returning Marker component as shown in the code snippet below:

          {this.state.campings.map(marker => (
              <Marker
                key={`marker-${marker.id}`}
                coordinate={marker.latlng}
              >
                {campingMarker(marker)}
              </Marker>
            ))}

Here, the marker icons in the location will change based on the value in the campings state.

Handling the display of markers

Next, we need to handle the display of marker icons based on the header tab buttons. We might have remembered that we have defined the function called handleTab() which takes in the tab key value in order to change the style of the active tab. Now, we need to make some additional configurations to the handleTab() function show that it will handle the change of active tab button style as well as display the appropriate markers in the map. For that, we need to use the code from the following code snippet:

handleTab = (tabKey) => {
    let newCampings = campings;
    if(tabKey != 'all'){
      newCampings = campings.filter(camping => camping.type == tabKey)
    }
    this.setState({ active: tabKey, campings : newCampings});
  }

Here, we have assigned a new variable named newCampings to the original campings array. Then, we have filtered the original campings array using the filter() array function and assigned it to the newCampings variable based on the tabKey value. Now, if the tabKey is not equals to ‘all’ type then the campings array is filtered based on tabKey value and returned to the newCampings array else newCampings array is equal to the original campings array data. Lastly, we assign a change of state using the setState function.

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

As we can see, the location markers in the map change as we click on the header tab buttons. Finally, we have successfully completed the implementation of Map Markers in our Camping Spots Finder App UI clone.

Conclusion

This tutorial is the fourth and final part of the Camping Spot Finder App UI clone tutorial series. In this part, we continued from where we left off in the third part of this tutorial series. In the part of the tutorial, we first learned how to add icons to the button and switch the icon styles based on the active button. Then, we got detailed insight on how to implement the Marker component from the react-native-maps package in order to show location marker on the map. We also got to learn how to display a unique icon as a marker on the map. And lastly, we got the guidance on how to change the location markers based on the active tab buttons.

This wraps up this final part of our Camping Spots Finder app UI clone tutorial series. In doing so, we have finally completed the overall tutorial for the cloning of Camping Spots Finder app UI.

Hope you enjoyed this tutorial series!! See you in the next one!!

The post Camping Spots Finder App UI Clone with React Native #4 : Map Marker appeared first on Kriss.

Disclosure

This post includes affiliate links; I may receive compensation if you purchase
products or services from different links provided in this article

Top comments (0)