React Native Car Parking Finder App UI Clone #4 : Map Markers

Written by absek | Published 2019/11/11
Tech Story Tags: react | react-native | mobile-application-development | tutorial | ui-clone | apps | mobile-apps

TLDR This tutorial is the fourth part of our React Native Car Parking App UI clone series. The inspiration of this tutorial came from the React Native App Templates that provides us with an amazing, fully-coded starter kit written in React Native. In this part of the tutorial series, we are going to add the custom Map Marker which will represent the car parking spot locations on the map. The idea is to integrate the Marker component provided by MapView component into the MapView in order to show the default location markers.via the TL;DR App

This tutorial is the fourth part of our React Native Car Parking App UI clone series. In the last part, we successfully implemented the car parking spots section. In this part of the tutorial series, we are going to continue from where we left off in the last part. So, it is recommended to go through the previous parts of this tutorial series in order to get the full insight and development of the project.
As mentioned in the previous parts, the inspiration of this tutorial came from the React Native App Templates that provides us with an amazing, fully-coded starter kit written in React Native that anyone can use to build their own store locator React Native application or initiate their own startup. 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. The video tutorial uses a fast coding style to deliver the overall tutorial to the viewers which may be difficult to grasp for any developer especially the beginners. This tutorial gives step by step guidance on the implementation of each UI section. Hence, the readers can relax and take time to implement the UI.
Overview
In this fourth part of the tutorial series, we are going to add the custom Map Marker which will represent the car parking spot locations on the map. The idea is to integrate the Marker component provided by MapView component into the MapView in order to show the default location markers. Then, we are going to customize the markers in order to make it as in the actual app. Lastly, we are going to add the active style to each map marker.
So, let us begin!!

Changing SrollView to FlatList

Firstly, we are going to make an extra change to our
ScrollView
in renderParkings() method. Here, we are going to change the
ScrollView 
into
FlatList
 in order to change our parking spot cards in the parking section into the list. By changing it into 
FlatList
, we will get all the advantages offered by 
FlatList
 component as well as can include the 
ScrollView
 props into the 
FlatList
 component. The coding implementation for this is provided in the code snippet below:
renderParkings(){
      return(
        <FlatList
          horizontal
          pagingEnabled
          scrollEnabled
          showsHorizontalScrollIndicator={false}
          scrollEventThrottle={16}
          snapToAlignment="center"
          style={styles.parkings}
          data={parkingsSpots}
          keyExtractor={(item, index) => `${item.id}`}
          renderItem={({ item }) => this.renderParking(item)}
        />
      )
}
Here, we have replaced the 
ScrollView
 with 
FlatList
 component. Most of the required props that we integrated to the 
ScrollView
 for a smooth swiping transition are also incorporated in the 
FlatList
 component. The extra props that we have added are the data for the parkingsSpots, keyExtractor in order to identify each item in the list uniquely and renderItem which will return the template. 
FlatList
 loops through each element of our parkingsSpots array and return the list view which can be customized as a template in the renderItem prop.
Note that, we should not forget to import the FlatList component from the react-native package.
Now, we are also going to add react hook called componentWillMount(), which will change the state of our hours state to 1 as shown in the code snippet below:
componentWillMount() {
    const hours = {};
    parkingsSpots.map(parking => {hours[parking.id] = 1});
    this.setState({ hours });
  }
Now, we should get the same result as we did before with
ScrollView
. Hence, if we re-run the emulator, we will get the following result in our emulator screen:

Adding the Map Markers

Here, we are going to add the Map Marker to our 
MapView
 component. For this, we will need to add some additional coordinate data to our parkingsSpots array data as provided in the code snippet below:
const parkingsSpots = [
  {
    id: 1,
    title: 'Parking 1',
    price: 5,
    rating: 4.2,
    spots: 20,
    free: 10,
    coordinate: {
      latitude: 37.78735,
      longitude: -122.4334,
    }
  },
  {
    id: 2,
    title: 'Parking 2',
    price: 7,
    rating: 3.8,
    spots: 25,
    free: 20,
    coordinate: {
      latitude: 37.78845,
      longitude: -122.4344,
    }
  },
  {
    id: 3,
    title: 'Parking 3',
    price: 10,
    rating: 4.9,
    spots: 50,
    free: 25,
    coordinate: {
      latitude: 37.78615,
      longitude: -122.4314,
    }
  },
];
Here, we have added the coordinate object containing latitude and longitude value of each parking spot.

Implementing Marker

Now, we are going to add the Marker component to 
MapView
 component. For that, we need to define the Marker component which can be imported from 
MapView
 component as shown in the code snippet below:
const {Marker} = MapView;
The 
MapView
 component imported from the react-native-maps package also provides the Marker module. This Marker module enables us to add different location markers to the screen.
Now, we are going to use the Marker component inside for 
MapView 
component. Since we have 3 parking spots data in order parkingsSpots array, we need to use map() array function to iterate through all the items. Then, the map() array function will return the 
Marker
 component as shown in the code snippet below:
render(){
    return (
      <View style={styles.container}>
        {this.renderHeader()}
        <MapView style={styles.map}
            initialRegion={{
                latitude: 37.78825,
                longitude: -122.4324,
                latitudeDelta: 0.0922,
                longitudeDelta: 0.0421,
            }}
        >
          {parkingsSpots.map(parking =>
            <Marker 
              key={`marker-${parking.id}`}
              coordinate={parking.coordinate}/>
            )}
        </MapView>
        {this.renderParkings()}
      </View>
    );
  }
}
Here, the 
Marker
 component has two props. One prop is key which identifies each marker uniquely. The other is coordinate prop which will take the latitude and longitude value to display the location marker on the screen.
Hence, we will get the following result in the emulator screen:
Since we are looking at the map from far away, the map markers look very close to each other. So, let us zoom into the map and the markers will be separate out to the more specific location as shown in the emulator screenshot below:
As we can see, we have got the markers in the MapView marking the exact location as provided in the coordinates. But, the marker icon on the screen is actually the default marker icon.
Now, we are going to customize the icon in order to make it look like in the actual app.

Customizing Marker Icon

Here, we are going to make some customization to the map marker icon. We are going to add our own components and styles in order to make the marker icon appear as in the actual app. For that, we need to use the code from the following code snippet in the
Marker
component:
  {parkingsSpots.map(parking =>
            <Marker 
              key={`marker-${parking.id}`}
              coordinate={parking.coordinate}>
                <View style={styles.marker}>
                  <Text>${parking.price}</Text>
                  <Text>({parking.free}/{parking.spots})</Text>
                </View>
            </Marker>
           )}
Here, we have added a 
View
 component inside the 
Marker
 component. The 
View
 component wraps two 
Text
 components having the price, free parking spots and total parking spots value. There are some styles used as well, which is provided in the code snippet below:
marker : {
    backgroundColor : 'white',
  }
Hence, we will get the following result in our emulator screen:
As we can see, the customized map markers have appeared on the screen with price as well as parking spots value. But, this does not look appealing. So, we are going to configure them by adding some extra styles.
Adding styles
Here, we are going to add some extra styles to the components of the marker icon template. We are going to add styles to the 
View
 component and the 
Text 
components that we added earlier as shown in the code snippet below:
<Marker 
              key={`marker-${parking.id}`}
              coordinate={parking.coordinate}>
                <View style={[
                  styles.marker,
                  styles.shadow,
                ]}>
                  <Text style={styles.markerPrice}>${parking.price}</Text>
                  <Text style={styles.markerStatus}> ({parking.free}/{parking.spots})</Text>
                </View>
            </Marker>
Here, we have added two style properties to View component and one each to the Text component. The required style properties are provided in the code snippet below:
 marker: {
    flexDirection: 'row',
    backgroundColor: '#FFFFFF',
    borderRadius: 24,
    paddingVertical: 12,
    paddingHorizontal: 24,
    borderWidth: 1,
    borderColor: '#FFFFFF',
  },
  markerPrice: { 
    color: '#D83C54', 
    fontWeight: 'bold', 
  },
  markerStatus: { 
    color: '#7D818A'
  },
  shadow: {
    shadowColor: "#3D4448",
    shadowOffset: {
      width: 0,
      height: 6,
    },
    shadowOpacity: 0.1,
    shadowRadius: 4,
    backgroundColor : 'white',
    elevation : 5
  },
Note that, we have added a shadow style property here. If we run this application on iOS emulator then the shadow style properties will execute properly. But since we are using the android emulator, we will have to use the elevation style property for the shadow. But this elevation style property for implementing shadow in the Android platform does not seem to work in the expo. This may be due to the version problem. So, if adding the shadow style is mandatory then, it is recommended to use the external packages like react-native-shadow. Here, we are not going to use it as the shadow style is not mandatory.
Therefore, we will get the following result in the emulator screen:
As we can see, the map markers look very attractive now with the price and parking spots availability information. This template for the markers seems good without the shadow. But, if we decide to run this in the iOS emulator, then the markers will look even more attractive with shadow style.

Configuring Active Parking Spot

Here, we are going to set up an active style for the markers whenever we click on any parking spots cards. With this, we will be able to know the parking location of each parking card on the map. The idea is to change the border color of our custom map markers whenever we click on any parking spot cards. This will help to identify the parking location of each parking spot card. For that, we need to define a state called active as shown in the code snippet below:
state = {
    hours: {},
    active : null
  }
Then, we need to import the necessary components from the react-native package as shown in the code snippet below:
import { 
 StyleSheet, 
 Text, View, 
 ScrollView, 
 Dimensions, 
 TouchableOpacity, 
 FlatList, 
 TouchableWithoutFeedback 
 } from 'react-native';
Now, we are going to change the active state whenever we click on any parking spot cards.
For that, we are going to add a
TouchableWithoutFeedback 
component wrapping the entire template in the renderParking() method. Then, we are going to add the key prop to 
TouchableWithoutFeedback
 component instead of the inner 
View
 component. Now, to change the active state we are going to use the setState function in the onPress event of the 
TouchableWithoutFeedback
 component. The setState function will set the active state variable to parking spot ID on the basis of which one is clicked. The overall coding implementation is provided in the code snippet below:
renderParking(item){
    const { hours } = this.state;
      return(
        <TouchableWithoutFeedback key={`parking-${item.id}`} onPress={() => this.setState({ active: item.id })} >
          <View style={[styles.parking, styles.shadow]}>
           .....
          </View>
        </TouchableWithoutFeedback>
      )
  }
Now, we need to add the required active style so that the border color of map markers changes when we click on any parking spot cards. The required style is provided in the code snippet below:
active: {
    borderColor: '#D83C54',
  },
Now, in the 
Marker
 component, we have a 
View
 component with style properties. Now, we are going bind another style property to it based on the active state as shown in the code snippet below:
           <Marker 
              key={`marker-${parking.id}`}
              coordinate={parking.coordinate}>
                <TouchableWithoutFeedback onPress={() => this.setState({ active: parking.id })} >
                  <View style={[
                    styles.marker,
                    styles.shadow,
                    this.state.active === parking.id ? styles.active : null
                  ]}>
                    <Text style={styles.markerPrice}>${parking.price}</Text>
                    <Text style={styles.markerStatus}> ({parking.free}/{parking.spots})</Text>
                  </View>
                </TouchableWithoutFeedback>
            </Marker>
Here, if the active state is equal to the parking ID value then the style we defined before will appear. Else, the style will be null. Here, we have also wrapped the entire marker icon template inside 
Marker
 component with the 
TouchableWithoutFeedback
 component. This will perform the same function as in the 
TouchableWithoutFeedback
 component in renderParking() method. The only difference is that the active style is triggered when we press on any map markers.
There is also a small change made in the style property which is provided in the code snippet below:
parkings :{
    position: 'absolute',
    right: 0,
    left: 0,
    bottom: 24,
    paddingBottom : 24
  },
Hence, we will get the following result in our emulator screen:
As we can see, when we click on parking spot cards the specific location map marker is active with border color.
Finally, we have successfully implemented the map markers in the 
MapView
 component of the map screen with active style as well. With this, we have come to the end of this part of our tutorial series. Most of the UI sections in the map screen is complete now.

Conclusion

This tutorial is the fourth part of the React Native Car Parking 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 this part of the tutorial, we learned how to replace the 
ScrollView
 and make use of 
FlatList
 with the same props. Then, we got step by step guidance on adding custom map markers to the map. Lastly, we also learned to configure the active style to map markers whenever the parking spot card or marker is pressed.
In the next part of this tutorial series, we are going to configure inline styles in the 
Stylesheet
 component as well as implement the Header section.


Written by absek | Vue | React Native developer
Published by HackerNoon on 2019/11/11