Welcome to part 3 of this series.

If you have been following through the previous parts, you know that we are building a full features authentication app using React Native and AWS Amplify.

If you did not follow the two previous parts, I suggest you start here.

You can check the full repo in here.

We are still in the process of scaffolding the front end of our project. We left it where we finished designing the authentication screens.

In this part, we will start by adding the app logo and make it fade in and out depending on the View position. Then we will redesign the layout of the App stack to make it look more appealing. Finally, we will finish by adding an international phone input with country code.

So let us get started 🐎.

4.6 — Animated logo for the authentication flow

The how and what design for the logo is your choice. However, if you don’t want to spend too much time on this, I provide my own design under the components directory of the project on my Github. Check it out in here.

Now, this logo will be displayed on several of our screens.

Create a new folder inside the components directory and name it images.

Put the logo.png inside the images folder.

Now import it on top of the class-based components of the following files: SignInScreen.js, SignUpScreen.js, ForgetPasswordScreen.js, WelcomeScreen.js.

// Load the app logo

const logo = require('../images/logo.png') export default class ClassName extends React.Component {

... rest of the code

Inside the state of the SignUpScreen and ForgetPasswordScreen components, add the following fields.

state = {

username: '',

password: '',

fadeIn: new Animated.Value(0), // Initial value for opacity: 0

fadeOut: new Animated.Value(1), // Initial value for opacity: 1

isHidden: false

}

We will be using the React Native Animated (imported previously in part 2) component to make the fade in and fade out effects. Two fields are initialized with an initial value for the opacity. The third field is a boolean that checks the state of the logo.

The animation for the SignInScreen component is different. Both fade in and fade out states will start with value 0 for the opacity. This is to add a nice blinking effect when focusing on the Input fields.

Inside the state of the SignInScreen component, add the following fields.

state = {

username: '',

password: '',

fadeIn: new Animated.Value(0),

fadeOut: new Animated.Value(0),

isHidden: false

}

Inside the SignInScreen, SignUpScreen, and ForgetPasswordScreen components add the following methods.

componentDidMount() {

this.fadeIn()

} fadeIn() {

Animated.timing(

this.state.fadeIn,

{

toValue: 1,

duration: 1000,

useNativeDriver: true

}

).start()

this.setState({isHidden: true})

} fadeOut() {

Animated.timing(

this.state.fadeOut,

{

toValue: 0, // 1 in the SignInScreen component

duration: 700,

useNativeDriver: true

}

).start()

this.setState({isHidden: false})

}

Upon mounting, componentDidMount will call a method named fadeIn. This method sets the opacity to 1 gradually taking this value from 0 within a timeframe we set in the duration prop. Then it will update the state by setting isHidden to true.

Notice we added the useNativeDrive prop and set it to true. This will allow us to have better performance for the animations on the actual device. More on this prop in the following link.

The fadeOut method does the opposite. It gradually takes the opacity from 1 to 0 within a defined duration. Then sets the isHidden prop to false.

Ok, let us now use these methods to animate the app logo.

In SignInScreen.js, SignUpScreen.js, and ForgetPasswordScreen.js add the following destructuring statement inside the render() method.

let { fadeOut, fadeIn, isHidden } = this.state

We start by adding the app logo to the WelcomScreen.js. This screen won’t have an animation effect and hence we only need to import the Image component.

import {

...same code as before

Image

} from 'react-native'

Render the app logo by adding the Image component inside the render() method of the class WelcomScreen component. The logo source, defined earlier, is passed as a prop to the Image component.

render() {

return (

<View style={styles.container}>

{/* App Logo */}

<Image source={logo}/> ... Rest of the code

For the SignInScreen screen, we want the logo to change size when the user focuses on the Input fields.

To achieve this, add the following code inside the View component just on top of the Container.

<View style={styles.container}>

{/* App Logo */}

<View style={styles.logoContainer}>

{

isHidden ?

<Animated.Image source={logo} style={{ opacity: fadeIn }}/>

:

<Animated.Image

source={logo}

style={{ opacity: fadeOut, width: 113.46, height: 117 }}/>

}

</View>

{/* Infos */}

<Container style={styles.infoContainer}>



... rest of the code

We conditional rendering to check if the logo is hidden or not, then we rendered the Animated.Image component with specific height and width.

We will follow a similar approach for the ForgetPasswordScreen and SignUpScreen components. However, we won’t change the dimensions of the logo.

In ForgetPasswordScreen.js, add the following code just inside the View component.

<View style={styles.container}>

{/* App Logo */}

<View style={styles.logoContainer}>

{

isHidden ?

<Animated.Image source={logo} style={{ opacity: fadeIn }}/>

:

<Animated.Image source={logo} style={{ opacity: fadeOut }}/>

}

</View>

{/* Infos */}

<Container style={styles.infoContainer}>



... rest of the code

In SignUpScreen.js, add the following code just below the View component. We set smaller dimensions for the logo as the SignUpScreen has several components.

<View style={styles.container}>

{/* App Logo */}

<View style={styles.logoContainer}>

{

isHidden ?

<Animated.Image

source={logo}

style={{ opacity: fadeIn, width: 110.46, height: 117 }}

/>

:

<Animated.Image

source={logo}

style={{ opacity: fadeOut, width: 110.46, height: 117 }}

/>

}

</View>

{/* Infos */}

<Container style={styles.infoContainer}>



... rest of the code

Now we will add the necessary callbacks to trigger these animation effects.

Remember, to take user input such as username, password ..etc, we defined Input components in the SignInScreen, SignUpScreen, ForgetPasswordScreen.

We want the logo to animate when the user focuses on these Input fields.

Add the following callbacks to all these Input fields.

<Input

... same code as before

onFocus={() => this.fadeOut()}

onEndEditing={() => this.fadeIn()}

/>

Now time to test the animated logo. Run your simulator and navigate to the welcome page. You should be able to see similar behavior to the below video.

Animated logo for the authentication flow.

Cool isn't it 😉.

4.7 — Tab navigation layout in the Auth stack

We did enough styling for the Auth stack. Now time to style our App Stack.

Sign in to the app. The App stack so far has the following look.

App stack as for now.

In App.js we had the following imports for navigating in the Auth and App stacks using react-navigation.

import {

createSwitchNavigator,

createStackNavigator ,

createDrawerNavigator,

createBottomTabNavigator

} from 'react-navigation'

The bottom tabs for the App stack have been defined in part 1 of this series using the createBottomTabNavigator component of react-navigation 2.

In App.js, the AppTabNavigator code looked like this.

// Bottom App tabs

const AppTabNavigator = createBottomTabNavigator({

Home: {

screen: HomeScreen

},

Profile: {

screen: ProfileScreen

},

Settings: {

screen: SettingsScreen

}

})

In order to have more control over the design of the tabs, we will remove createBottomTabNavigator and replace it with the createMaterialTopTabNavigator.

In App.js, delete the createBottomTabNavigator import and replace it with the new import.

import {

createSwitchNavigator,

createStackNavigator ,

createDrawerNavigator,

createMaterialTopTabNavigator // new import

} from 'react-navigation'

Replace the AppTabNavigator code, which will now be defined using the createMaterialTopTabNavigator, with the following.

// New bottom App tabs design

const AppTabNavigator = createMaterialTopTabNavigator(

configurations, options

)

For a video walkthrough on how to create a navigation tab with createMaterialTopTabNavigator, I encourage you to check unsure programmer video tutorial by clicking the following link.

As stated in the react navigation docs, the createMaterialTopTabNavigator takes two arguments: RouteConfigs, TabNavigatorConfig.

In our App.js, we named these two arguments: configurations and options.

Add the following code for configurations and options in App.js immediately on top of AppTabNavigator.

The final design of the Auth stack with createMaterialTopTabNavigator.

Let us walk through the code in the above gist.

In configurations, we defined our application screens: Home, Profile, Settings.

Through navigationOptions, we added a screen label and a screen icon to each one of these screens.

By passing the tinColor as an argument in tabBarIcon to the color prop, we are able to change the Icon color of the active screen with respect to the inactive screens. This change in color information is passed from the options object through the activeTintColor and inactiveTintColor.

In options, we defined the styling of the different components of the AuthTabNavigator such as the tabBarPosition, the swipeEnabled, the labelStyle …etc.

One last thing before testing. We want the common header’s title to change depending on the active screen.

To achieve this, I managed to find a solution that works quite well. Add the following code right below AppTabNavigator.

// Bottom App tabs

const AppTabNavigator = createMaterialTopTabNavigator(configurations, options) // Making the common header title dynamic in AppTabNavigator

AppTabNavigator.navigationOptions = ({ navigation }) => {

let { routeName } = navigation.state.routes[navigation.state.index]

let headerTitle = routeName

return {

headerTitle,

}

}

Now refresh your simulator. The App stack layout now looks like this.

App stack final design.

Looks great 😉.

When you try and navigate to the Profile and Settings screen, then back to the Home screen. You should be able to see:

A cool swipe effect when navigating.

The active screen has its Icon highlighted with white.

The header title will change accordingly.

4.8 — Adding an international phone input with country code

For this part, the focus will be solely on the SignUpScreen.js.

I have made a full independent tutorial on how to build a React native phone input with country code. I highly recommend checking it in here.

To register users from different countries, we need the necessary data about their countries: name, flag, and country phone code.

Create a new file in the components folder and name it countryCode.js.

Fill this file with the country data from the following link.

Import the countryCode.js in SignUpScreen.js and define a default flag to be rendered from the countries data using the javascript filter function.

The following code is to be added on top of the SignUpScreen class component.

// Load the app logo

const logo = require('../images/logo.png') // Default render of country flag

const defaultFlag = data.filter(

obj => obj.name === 'United Kingdom'

)[0].flag export default class SignUpScreen extends React.Component {

... rest of the code

We will be using react-native Modal and Flatlist components. Remember we already imported these components in our SignUpScreen.js in part 2 section 4.3.

Add the default flag as a state field inside the SignUpScreen class component. We will also add a boolean field called modalVisible that will be used to toggle open/close the Modal component.

state = {

... same code as before

flag: defaultFlag,

modalVisible: false,

}

Add the following methods inside the SignUpScreen class component.

// Functions for Phone Input

showModal() {

this.setState({ modalVisible: true })

console.log('Shown')

} hideModal() {

this.setState({ modalVisible: false })

// Refocus on phone Input after modal is closed

this.refs.FourthInput._root.focus()

console.log('Hidden')

} async getCountry(country) {

// Get the country flag and phone code from users selection

const countryData = await data

try {

const countryCode = await countryData.filter(

obj => obj.name === country

)[0].dial_code

const countryFlag = await countryData.filter(

obj => obj.name === country

)[0].flag

// Set data from user choice of country

this.setState({ phoneNumber: countryCode, flag: countryFlag })

await this.hideModal()

}

catch (err) {

console.log(err)

}

}

In the above code snippet, the two first methods, namely showModal and hideModal, are self-explanatory. Their only job is to set the modalVisible to true or false respectively.

The only additional code in hideModal is to refocus the user on the phone input when the modal is closed.

The third method getCountry() takes as argument a given country (based on the users' selection) and filters the data to get the flag and dial_code of that country. When the user selects the country of choice, this method calls the hideModal to close the modal.

Inside the render() method, add the flag state field to the destructuring statement and assign the country data, imported earlier, to a variable called countryData.

let { fadeOut, fadeIn, isHidden, flag } = this.state

const countryData = data

Now add the following components inside the phone Item.

<Item rounded style={styles.itemStyle}>

<Icon

active

name='call'

style={styles.iconStyle}

/>

{/* country flag */}

<View><Text>{flag}</Text></View>

{/* open modal */}

<Icon

active

name='md-arrow-dropdown'

style={[styles.iconStyle, { marginLeft: 0 }]}

onPress={() => this.showModal()}

/>

The code above is to display the country flag and a drop down Icon for the Modal.

Still inside the phone Item, just below the phone Input, we will add the Modal component.

Modal component for country international phone input.

In the above code, we looped through the countryData using the FlatList component. For each item from the countryData (i.e. a country), we rendered the country flag, the country name, and the country dial_code.

We wrapped these data with a TouchableWithoutFeedback and passed the getCountry method as the onPress to get the user’s selection.

Notice that the visible prop in the Modal component is set to true or false depending on the modalVisible state field.

Now refresh your app. Go to the sign-up screen. You should see the following behavior.

International phone input in the sign-up screen.

Et voila 😎.

Conclusion

In this part 3 of the series, we added an animated logo, redesigned the layout of the App stack, and added an international phone input to the sign-up screen.

This will conclude the front end design of our authentication app.

The last part of this series will be solely focused on integrating AWS Amplify as the back end service of our app to authenticate and store users credentials.

If you enjoyed this tutorial, you can give me as many claps👏 as 50. Hit the follow button to stay updated with the upcoming articles. You can stay updated with my latest open source projects on Twitter and Github.

Thank you for reading and stay tuned for the last part 👋.

Join our community Slack and read our weekly Faun topics ⬇