This tutorial is the sixth part of our React Native Car Parking App UI clone series. In the last part, we successfully implemented the Header section in our map screen as well as organized our code. 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 all 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 motivation for this tutorial series came from the React Native App Templates that provides us with a dynamic, 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 sixth part is also the continuation of coding implementations and designs from the YouTube video tutorial by React UI Kit for the Car parking Finder App UI clone. The video tutorial seems to deliver the implementations of different UI sections using a fast coding style that may be difficult to understand for any developer especially the beginners. However, this tutorial gives step by step guidance on the implementation of each UI section. Hence, the readers can relax and take time to learn and implement the UI.
Overview
In this sixth part of the tutorial series, we are going to implement a Modal that displays extended information of the parking card section with different UI sections. The idea is to install the react-native-modal package and integrate it into the map screen. Then, we are going to configure the Modal in order to make it look like in the actual app. Lastly, we will implement different sections inside the Modal view and style them.
So, let us begin!!
Here we are going to install the react-native-modal package into our project. This package provides an enhanced, animated and customizable react-native modal. The main aim of this package is to is expanding the original react-native
Modal
component by adding animations and styles customization options while still providing a plain-simple API. Now in order to install this package into our project, we need to run the following command:expo install react-native-modal
Then, we need to import this package as Modal component in the Map.js file as shown in the code snippet below:
import Modal from 'react-native-modal';
In this step, we are going to implement the modal into our Map screen. For that, we need to define a state called activeModal in order to handle the opening and closing of the modal. The activeModal should be defined as shown in the code snippet below:
state = {
hours: {},
active : null,
activeModal : null
}
Now, we need to activate the modal when pressing the buy button on our parking spot card. For that, we need to change the state of activeModal in the onPress event of
TouchableOpacity
component as shown in the code snippet below: <TouchableOpacity style={styles.buy} onPress={() => this.setState({ activeModal: item })}>
<View style={styles.buyTotal}>
<Text style={styles.buyTotalPrice}>${item.price *2}</Text>
<Text style={{ color : theme.COLORS.white}}>{item.price}x{hours[item.id]} hrs</Text>
</View>
<View style={styles.buyButton}>
<Text style={{fontSize: 25, color : theme.COLORS.white}}>></Text>
</View>
</TouchableOpacity>
Here, we have just implemented a trigger to open the modal but have not implemented the actual
Modal
component yet. So now, we are going to implement the actual modal.Defining a new function for modal
Here, we are going to define a new function called renderModal(). This function will return the template with the
Modal
component. The overall implementation of this function is provided in the code snippet below:renderModal(){
const {activeModal} = this.state;
if (!activeModal) return null;
return(
<Modal
isVisible
onBackButtonPress={() => this.setState({ activeModal: null })}
onBackdropPress={() => this.setState({ activeModal: null })}
>
<View style={styles.modal}>
<Text>{activeModal.title}</Text>
</View>
</Modal>
)
}
Here, inside the renderModal() method, we have defined activeModal constant from the state variable. Then, if the activeModal state is empty then the renderModal() function will return null which will not show the
Modal
on the app screen. However, if the activeModal state is not empty, the function will return the template with Modal
component. The Modal
component here is configured with different props.The isVisible prop is used to show the modal on the screen. In the onBackButtonPress and onBackdropPress events of the
Modal
component we have changed the activeModal state to null in order to hide the Modal
from the screen. We have also integrated some View
component wrapping Text component with some inline styles.Now, we need to call the renderModal() method in the render() function of our
Map.js
file as shown in the code snippet below:render(){
return(
…………
{this.renderParkings()}
{this.renderModal()}
</View>
)
}
Now, the required style used in the renderModal() function is provided in the code snippet below:
modal : {
backgroundColor : theme.COLORS.white
}
Hence, we will get the following result in the emulator screen:
As we can see, a modal appears on the screen. But the modal is too small, so we need to configure it with more props and style in order to make the modal more appealing.
Configuring Modal properties and styles
Here, we are going to configure the
Modal
component with some additional props and styles. For that, we need to use the code from the following code snippet:renderModal(){
const {activeModal} = this.state;
if (!activeModal) return null;
return(
<Modal
isVisible
useNativeDriver
style={styles.modalContainer}
onBackButtonPress={() => this.setState({ activeModal: null })}
onBackdropPress={() => this.setState({ activeModal: null })}
onSwipeComplete={() => this.setState({ activeModal: null })}
>
<View style={styles.modal}>
<Text>{activeModal.title}</Text>
</View>
</Modal>
)
}
Here, we have included a prop called useNativeDriver which uses the native driver configurations and properties to handle the workings of Modal. We have also included a inSwipeComplete event which changes the activeModal state to null. Then, we have also provided a style property to the
Modal
component which is provided in the code snippet below:modalContainer: {
margin: 0,
justifyContent: 'flex-end',
},
modal: {
height: height * 0.75,
backgroundColor: theme.COLORS.white,
},
Hence, we will get the following result in the emulator screen:
As we can see, the Modal component now covers more than half of the lower part of the screen.
Now, we are going to add some content inside the Modal view. We have added the trigger to open the Modal when we press the buy button in each car parking spot. When triggering, we have set the activeModal state to the particular parking spot data from the parkingsSpots data array. Now, we are going to use the value stored in the activeModal state in order to add the different parking spot information to the Modal. For that, we need to use the code from the following code snippet in the renderModal function:
renderModal(){
const {activeModal , hours} = this.state;
if (!activeModal) return null;
return(
<Modal
isVisible
useNativeDriver
style={styles.modalContainer}
onBackButtonPress={() => this.setState({ activeModal: null })}
onBackdropPress={() => this.setState({ activeModal: null })}
onSwipeComplete={() => this.setState({ activeModal: null })}
>
<View style={styles.modal}>
<View>
<Text>{activeModal.title}</Text>
</View>
<View>
<Text>{activeModal.description}</Text>
</View>
<View style={{flexDirection : 'row'}}>
<Text>{activeModal.price}</Text>
<Text>{activeModal.rating}</Text>
<Text>{activeModal.distance}</Text>
<Text>{activeModal.free}/{activeModal.total}</Text>
</View>
<View>
<Text>Choose your Booking Period</Text>
</View>
<View>
<TouchableOpacity style={styles.buy}>
<View style={styles.buyTotal}>
<Text style={styles.buyTotalPrice}>${activeModal.price *2}</Text>
<Text style={{ color : theme.COLORS.white}}>{activeModal.price}x{hours[activeModal.id]} hrs</Text>
</View>
<View style={styles.buyButton}>
<Text style={{fontSize: 25, color : theme.COLORS.white}}>></Text>
</View>
</TouchableOpacity>
</View>
</View>
</Modal>
)
}
Here, we have added different
View
and Text
component to display the information in the parkingsSpots data array. We have also used the TouchableOpacity
component which wraps the View
and Text
component for the final buy button in the Modal. The components are bound to different styles which are provided in the code snippet below:modal: {
flexDirection: 'column',
height: height * 0.75,
padding: theme.SIZES.base * 2,
backgroundColor: theme.COLORS.white,
borderTopLeftRadius: theme.SIZES.base,
borderTopRightRadius: theme.SIZES.base,
},
Hence, we will get the following result in our emulator screen:
As we can see, some content has appeared on the screen but are out of place. Now, we need to style them properly in order to make the Modal content look appealing as in the actual app.
Here, we can also notice that we have added the additional distance and description data in the Modal content. But these data are not included in the parkingsSpots data array. So, we need to include that first.
Here, we are going to add the distance and description data to each item in the parkingsSpots data array as shown 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,
},
distance : 2.5,
description: `Description about this parking lot
Open year 2018
Secure with CTV`,
},
{
id: 2,
title: 'Parking 2',
price: 7,
rating: 3.8,
spots: 25,
free: 20,
coordinate: {
latitude: 37.78845,
longitude: -122.4344,
},
distance : 3.5,
description: `Description about this parking lot
Open year 2018
Secure with CTV`,
},
{
id: 3,
title: 'Parking 3',
price: 10,
rating: 4.9,
spots: 50,
free: 25,
coordinate: {
latitude: 37.78615,
longitude: -122.4314,
},
distance : 1,
description: `Description about this parking lot
Open year 2018
Secure with CTV`,
},
];
Here, we are going to style the components inside the
Modal
component in order to make the Modal content appear as in the actual app. For that, we need to use the code in the following code snippet:<Modal
isVisible
useNativeDriver
style={styles.modalContainer}
onBackButtonPress={() => this.setState({ activeModal: null })}
onBackdropPress={() => this.setState({ activeModal: null })}
onSwipeComplete={() => this.setState({ activeModal: null })}
>
<View style={styles.modal}>
<View>
<Text style={{ fontSize: theme.SIZES.font * 1.5 }}>
{activeModal.title}
</Text>
</View>
<View style={{ paddingVertical: theme.SIZES.base }}>
<Text style={{ color: theme.COLORS.gray, fontSize: theme.SIZES.font * 1.1 }}>
{activeModal.description}
</Text>
</View>
<View style={styles.modalInfo}>
<View style={[styles.parkingIcon, {justifyContent: 'flex-start'} ]}>
<Text style={{ fontSize: theme.SIZES.icon * 1.15 }}> ${activeModal.price}</Text>
</View>
<View style={[styles.parkingIcon, {justifyContent: 'flex-start'} ]}
<Text style={{ fontSize: theme.SIZES.icon * 1.15 }}> {activeModal.rating}</Text>
</View>
<View style={[styles.parkingIcon, {justifyContent: 'flex-start'} ]}>
<Text style={{ fontSize: theme.SIZES.icon * 1.15 }}> {activeModal.distance}km</Text>
</View>
<View style={[styles.parkingIcon, {justifyContent: 'flex-start'} ]}>
<Text style={{ fontSize: theme.SIZES.icon * 1.15 }}> {activeModal.free}/{activeModal.spots}</Text>
</View>
</View>
<View style={styles.modalHours}>
<Text style={{ textAlign: 'center', fontWeight: '500' }}>Choose your Booking Period:</Text>
</View>
<View>
<TouchableOpacity style={styles.payBtn}>
<Text style={styles.payText}>
Proceed to pay ${activeModal.price * hours[activeModal.id]}
</Text>
<FontAwesome name='angle-right' size={theme.SIZES.icon * 1.75} color={theme.COLORS.white} />
</TouchableOpacity>
</View>
</View>
</Modal>
Here, we have added different inline style properties as well as styles from the
StyleSheet
component. The required styles from the StyleSheet
component is provided in the code snippet below: modalInfo: {
flexDirection: 'row',
justifyContent: 'space-evenly',
paddingVertical: theme.SIZES.base,
borderTopWidth: 1,
borderBottomWidth: 1,
borderTopColor: theme.COLORS.overlay,
borderBottomColor: theme.COLORS.overlay,
},
modalHours: {
paddingVertical: height * 0.11,
},
payBtn: {
borderRadius: 6,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
padding: theme.SIZES.base * 1.5,
backgroundColor: theme.COLORS.red,
},
payText: {
fontWeight: '600',
fontSize: theme.SIZES.base * 1.5,
color: theme.COLORS.white,
}
Hence, we will get the following result in our emulator screen:
As we can see, we have got all the components in the proper positions which makes the Modal look more appealing. Now, we need to add icons to the Modal.
Here, we are going to add the icons to the respective UI sections in the Modal content. We have already imported the Ionicons package from the vector-icons package provided by the expo client. Now, we are going to include the Ionicons component as shown in the code snippet below:
<View style={styles.modalInfo}>
<View style={[styles.parkingIcon, {justifyContent: 'flex-start'} ]}>
<Ionicons name='ios-pricetag' size={theme.SIZES.icon * 1.1} color={theme.COLORS.gray} />
<Text style={{ fontSize: theme.SIZES.icon * 1.15 }}> ${activeModal.price}</Text>
</View>
<View style={[styles.parkingIcon, {justifyContent: 'flex-start'} ]}>
<Ionicons name='ios-star' size={theme.SIZES.icon * 1.1} color={theme.COLORS.gray} />
<Text style={{ fontSize: theme.SIZES.icon * 1.15 }}> {activeModal.rating}</Text>
</View>
<View style={[styles.parkingIcon, {justifyContent: 'flex-start'} ]}>
<Ionicons name='ios-pin' size={theme.SIZES.icon * 1.1} color={theme.COLORS.gray} />
<Text style={{ fontSize: theme.SIZES.icon * 1.15 }}> {activeModal.distance}km</Text>
</View>
<View style={[styles.parkingIcon, {justifyContent: 'flex-start'} ]}>
<Ionicons name='ios-car' size={theme.SIZES.icon * 1.3} color={theme.COLORS.gray} />
<Text style={{ fontSize: theme.SIZES.icon * 1.15 }}> {activeModal.free}/{activeModal.spots}</Text>
</View>
</View>
Here, we have provided the size and color props to the Ionicons component. The props are in accordance to our
COLORS
and SIZES
variable from the theme.js
file.Hence, we will get the following result in our emulator screen:
As we can see, we have got the icons in our
Modal
view. But we can see there is something missing in section with ‘Choose your Bookings Period’. In this section, we need to add the hours section as in the parking spot cards.Here, we are simply going to add the hours section to modal. We are going to add this section using below the
Text
component having ‘Choose your Booking Period’ text as shown in the code snippet below: <View style={styles.modalHours}>
<Text style={{ textAlign: 'center', fontWeight: '500' }}>Choose your Booking Period:</Text>
<View style={styles.modalHoursDropdown}>
<Text style={{ color: theme.COLORS.gray }}>5:00 hrs</Text>
</View>
</View>
Here, the
View
component wraps the Text
component with text showing hours. The required style is provided in the code snippet below:modalHours: {
paddingVertical: height * 0.15,
},
modalHoursDropdown: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
paddingVertical: theme.SIZES.base,
},
Hence, we will get the following result in our emulator screen:
As we can see, we have got the hours section in our Modal. With this, we have come to the end of this part of our tutorial.
Finally, we have successfully completed the implementation of Modal in our Map screen.
This tutorial is the sixth 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 fifth part of this tutorial series. In this part of the tutorial, we learned how to set up the react-native-modal package in order to implement the Modal in our Map screen. We also learned how to configure the Modal component in order to make it look as well as transition better. Then, we also got insight into adding different UI sections inside the
Modal
component. Finally, we were successful in implementing the Modal
view just as in the actual app design.In the next part of this tutorial series, we are going to implement a time dropdown in our parking spot card section.