Common React Native App Layouts: Calendar Page

In this series, you'll learn how to use React Native to create page layouts commonly used in mobile apps. The layouts you'll be creating won't be functional—instead, the main focus of this series is to get your hands dirty in laying out content in your React Native apps. 

If you're new to laying out React Native apps or styling in general, check out my previous tutorial:

To follow along with this series, I challenge you to try recreating each screen by yourself first, before you read my step-by-step instructions in the tutorial. You won't really benefit much from this tutorial just by reading it! Try first before looking up the answers here. If you succeed in making it look like the original screen, compare your implementation to mine. Then decide for yourself which one is better!

In this second part of the series, you'll create the following calendar page:

calendar page

Calendar apps are used to track events and appointments added by the user. You'll find different variations in the wild, but most of them will have the same elements as a physical calendar would: the current month and year, the days in the month, and the events or appointments added by the user.

Here are a couple of examples of this type of layout:

google calendar
android calendar

Project Setup

The first step, of course, is to set up a new React Native project:

Once the project is set up, open the index.android.js file and replace the default code with the following:

Create a src/pages folder and create a Calendar.js file inside it.

You'll also need the react-native-vector-icons package. This is specifically used for the navigation icons as well as other icons that will be needed in the page.

Open the android/app/build.gradle file and add a reference to the package:

Do the same with the android/settings.gradle file by adding the following at the bottom:

Open android/app/src/main/java/com/react-native-common-screens/MainApplication.java and import the package:

Lastly, initialize the package: 

Creating the Calendar Page

Okay, now that you've tried to code the layout yourself (no cheating, right?), I'll show you how I built my implementation.

At first, I thought this would be the most difficult one to implement, but trust me, it's really not that complicated as long as you already know the basics. There are a couple of opportunities here to use JavaScript code to help with rendering. 

Start by including all the components and packages that you'll need:

This time there's a new package which you haven't installed yet, and that is lodash. You won't really need the whole lodash library, just the range function. This is used for generating an array of numbers based on a specific range. You can install just this function by executing npm install --save lodash.range on your terminal.

Add the boilerplate code for creating pages:

The header has three elements in it: the button for going back to the previous page, the title of the current page, and the text showing a human-friendly representation of the currently selected date.

calendar page initial look

header has a flexDirection of row so that each header_item is stacked horizontally. The same flex value is assigned to each of them so they consume equal amounts of space. text_center and text_right are used to align the text inside of those header_items to the center and right. This is done because by default they're aligned on the left-most side of their container.

Once the styles have been added, it should now look like this:

calendar page styled header

Next is the actual calendar, which is divided into three parts: the header, the days of the week, and the calendar days:

The calendar header allows the user to change the year and month. 

There are at least two ways this can be implemented. The first method is to treat each element as a single item and apply justifyContent: 'space-between' to its container. The second method is to group all the elements that have to do with the year and group those that have to do with the month. 

The second method is the one that's applied below. Semantically speaking, this makes much more sense because the button for navigating back a year, the year itself, and the button for navigating forward are all related, so you can treat them as a single thing by putting them in the same container. The same is true with the month controls.

calendar page added calendar header

From there, you can apply the same technique to those two groups of components in the same line. To add spaces between the two buttons (back and forward) and the label, we use justifyContent: 'space-between'. We use alignItems: 'center' to nudge all the elements inside it towards the center. Finally, we add left and right padding to add more space between the two groups.

calendar page added calendar header styles

Next are the weekdays. We use a function to render these because it's best to use some JavaScript code to render all the elements.

So instead of having seven View or Text components rendering each day of the week, you can just have an array containing the days of the week. You can then iterate through those days using the Array.map() function. For each iteration, render a Text component that shows the day. 

Note that in the code above, the toUpperCase() function is used to convert all the letters of each day to uppercase. React Native doesn't come with the text-transform CSS property, so this is the only way to achieve uppercase letters aside from manually using uppercase strings.

calendar page added calendar week days

Here's the styling for the calendar header:

calendar page styled calendar week days

The calendar days also uses a function for rendering the days:

The renderWeeks() function uses the range() function in lodash to generate an array containing the days from the last month and the days of the current month. Those two arrays are then merged together. 

However, you can't directly use the resulting array as the data source for the calendar days. That's because if you simply loop through the items and output a Text component for each day, there won't be any distinction between each week. You already know that to make each calendar day inline, you need to apply flexDirection: 'row' to its container. So applying it to a single container would result in having all the calendar days placed in a single line. 

This means you need to have a separate container for each week. The question is how. Again, there are at least two ways to accomplish this. 

The first method is to have a variable store how many days are currently outputted and then add a conditional statement that will render an opening <View> every time the variable contains 0 and a closing </View> every time it's 7. Once it's 7, reset it back to 0. This is the most straightforward method.

But I'll use a different method here. Below, the getWeeksArray() function is used to implement it. This function accepts the array of days and groups them into arrays containing seven days each. From there, you can loop through each of those arrays to render the week container. Then for each iteration, you again loop through the days inside the week to render the days. This is what the renderDays() function does.

Here's the getWeeksArray() function:

And here's the renderDays() function:

calendar page added calendar days

Add the styling for each week (week_days) and day (day and day_text):

calendar page add calendar days styling

Next is the note added by the user for the currently selected day and the selected date and time. Again, it's better to group elements according to their purpose rather than how they're placed in the page. Certainly all these elements are related, so we'll place them inside the same container. But on a closer look, you'll start to see that you can group them further: the actual note and the selected date. With that in mind, here's the markup that you'll end up with:

calendar page add notes

The selected date occupies less space than the note, so you have to apply a bigger flex value to the notes. flex: 3 and flex: 1 are used in this case, which means that the notes consume 3/4 of the available space and the selected date consumes 1/4. You can also use decimals (0.75 and 0.25) if that makes more sense to you. What's important is to pick a standard and stick to it. alignItems: 'flex-end' is used on notes_selected_date so that all its children will be aligned to the right. This is needed because by default they're aligned to the left.  

calendar page added styling to logs

Lastly, we add the logs, which are very similar to those in the previous tutorial, so I'll leave it to you to figure out how the layout is achieved!

Here are the styles:

Conclusion

That's it! In this tutorial you've created a calendar page. We've made a nice calendar layout for an app, and I've shown you how JavaScript code can be used to compensate for some of the limitations of Flexbox. 

As you have seen, we needed a way to limit the number of days in a row to just seven days. Flexbox doesn't have a way to specify this, so we used JavaScript to reconstruct the original array of days in such a way that they're divided into groups containing seven days each. From there, all we had to do was to wrap each group inside a View and then apply flexDirection: 'row' to make each of them render in their own row.

In an upcoming tutorial, you'll learn how to implement the layout commonly used in gallery pages. In the meantime, check out some of our other tutorials on React Native and Flexbox.

Tags:

Comments

Related Articles