Create an Animated Authentication Screen With NativeScript
This post will show you how to create an animated authentication screen, using NativesScript and Angular 2.
In the end, we want be able to able to swap the two screens (login and registration) by tapping on a control, like demonstrated on this video:
The whole source code is also available on GitHub at this address.
Let’s get started!
First step, create the application with the –ng flag:
Next, let’s go and install the nativescript-ng2-fonticon package as we’re going to use it later on.
When this is done, we’ll create our first Component, the
SessionComponent. To keep things organised, We’ll put it into a new
session directory, and let it empty for now:
Next, pack the
SessionComponent into a new Module:
We’ll now configure the Router, in order to get started on a healthy base. This is a better idea than polluting the
AppComponent with unrelated stuff just because we want to see something happening.
Create a file exporting our only route:
Next, import the
NativeScrpiptRouterModule, and import the
routes constant we’ve just created. We’ll also import the
Now we can edit the
AppComponent to display the
We’re now ready to get into the meat of our application.
Structure the SessionComponent
the session.component.html file with the following initial content:
To structure the screen, we use a GridLayout. We define two rows: one containing the login/registration forms, and one for the footer, enabling the switch to the new current screen (login or registration).
The login and registration forms will be hosted in their own components, and we’re going to wrap them into StackLayouts in order to easily control their apparition of the screen.
We also want to have both of them inside a GridLayout. This way, they will be displayed on top of each other, which is what we want (we’ll take care of the horizontal axis separation programmatically).
Let’s now create the
Create the LoginComponent
First, create the empty Component in a new
login directory, within the
session one. We’ll inject the
TNSFontIconService as we’re going to use it in the template:
We will use a
common.css stylesheet file instead of a login specific one, since we’ll reuse most of the styling for the register later on.
Next, create the login.component.html template:
And the styling:
Notice the use of
border-bottom-width for the form-container. The possibility to use per-side border definition in CSS is one of the awesome features coming out of the new NativeScript 2.4 release.
Let’s add the
LoginComponent to the
SessionModule declarations list:
And add the selector to inside the corresponding wrapper, that we created in the
Now, you can start the application, which should look like this:
It would be nice if we could also have the hint colors of the TextFields in white. Let’s create a directive for this. We’ll do it based on the following idea and separate the platform implementations into two distinct files.
Create the HintColorDirective
Create a new directory:
directives/hint-color. Then, start by creating the
HintColorBaseDirective, as suggested on the mentioned GitHub issue:
This is the abstract class that needs to be inherited from the ones representing each platform (android, and ios). The only thing that it does, is calling the abstract method
setColor(), passing the ElementRef (here, a TextField) and a new Color object created from the color code in input.
We can now define a child directive per platform.
Start with Android:
And then, iOS:
I think that it’s generally a good idea to make such a separation when dealing with platform specific code. This enables us to adapt only the specific file, when a change has to occur for one of the platforms.
Before being able to use the directive, we need to declare it into our
Note that we’re using a require instead of the ES6 import. This is because of the dynamic nature of the platform specific declaration. We need to do it this way in order to avoid TypeScript compilation error indicating that the module is not found.
We can now use the directive inside the
We should now have our white TextField hints:
Create the Footer
As mentioned on the introduction, we want to be able to switch the current screen by tapping on the footer. Let’s start by creating its layout. Go back to the
session.component.html file and edit its content like this:
The footer text will be dynamically updated according to the screen currently displayed, so we just set it to “My Text” for now.
Next, add the following styling:
Create the RegisterComponent
First, create the empty component:
Next, the template:
Then, we can declare the
To display the result, just comment out the #loginWrapper StackLayout in session.component.html, and add the register selector inside the #registerWrapper:
Ok, we’re now done with the template, let’s do something fun!
Animate the Screen Switching
Let’s add some animations to this static template. First, uncomment the #loginWrapper section in order to let the two StackLayouts visible. Then, open up
session.component.ts and add the following content:
Let’s break this down a little bit. Don’t worry about the code duplication for now, we’ll refactor this a bit later on.
First, the declarations:
We basically retrieve our two wrapper and add private getters in order to get the StackLayout objects out of them. We also declare a getter to get the actual screen width (using the
screen module). This will be helpful to create the animations simulating the ‘out of the screen’ translations. The last one,
screenToggled, is a flag indicating if the screen is toggled (from login, to register) or not.
Then, we have:
we translate the registerWrapper on the X-axis to the screen width, in order to take it out of the screen, to the right.
We use this method to trigger the screen change animation. We check the screenToggled flag. If we haven’t toggled yet (we’re on the initial screen, so the login screen), then we animate the loginWrapper to translate it to the left, to make it out of the screen (hence -this.screenWidth here). We bring at the same time (animate being asynchronous) the registerWrapper within the screen, at the initial position (x = 0). If the screen is already toggled, we bring the loginWrapper back to the screen, and we throw the registerWrapper away to the right of the screen. Finally, we change the flag value.
We now need to hook up this method to the (tap) event of the footer StackLayout:
And let’s see this in action:
Before we move on, let’s refactor this a bit:
At the very end, we create a
translateWrapper() method that takes a StackLayout in input, as well as an x position. We then call the animate method on the wrapper, and pass the given x value. we don’t need to pass any y value since the vertical position will stay the same anyway (0). We then use this method to build up three new ones:
bringInsideTheScreen() (leading to x = 0),
translateToTheRightOfTheScreen() (x = screenWidth) and
translateToTheLeftOfTheScreen() (x = – screenWidth).
Let’s now work on the animation of the footer text.
Fade In/Out the Footer Text
For the footer, we’re going to use a dynamic text, depending on wether the screen is toggled or not. Let’s first edit the template:
This way, we hook up the text attribute of the Label to the value of a
footerText Property that we will define in the Component.
Next, add the following lines to the
We’ve also added two getters representing the register and login displayed texts. Let’s now edit the toggleScreen() method to handle the footer toggle:
The toggleFooter() method takes a string in input. We first animate the
footerLabel to set its opacity to 0 (fade out), then change the
footerText to the given
newText, and finally, fade in the label. Notice that this time, we do the animations sequentially. We use a duration that is twice as short as the screen animation, so that it finishes exactly when the toggle is over (we have two animations here, the fade out, and the fade in).
Let’s see the result:
And again, let’s do a bit of refactoring:
fadeFooterTextTo() method, we need to return the result of
Before we move on, let’s also create a getter to isolate the screen toggle animation duration:
We also said that the fading animation duration should be half of the screen toggle duration, so let’s update the corresponding method:
We’re now done for the animation. Let’s now make the screen look a bit nicer.
Add a Neat Gradient Background
Let’s add a gradient background, cause that’s what cool kids do nowadays. By the time I’m writing this tutorial, NativeScript doesn’t support the gradient in CSS (but at the pace they bring in cool features, these lines might become obsolete very quickly. This means that we need to attack the native APIs. We’ll use the same pattern as for the
First, we’ll install the platform declarations:
references.d.ts to add the platform references:
According to this link, we also need to update the
tsconfig.json in order to avoid TypeScript compilation errors related to the platform definitions:
Now, let’s go ahead and create the
Next, create the
gradient-background.directive.android.ts file, hosting the Android native implementation:
gradient-background.directive.ios.ts for the iOS implementation:
It’s important to note that we’re using a workaround here: this iOS implementation uses the dimensions of the whole page (
view.page.ios.view.bounds) to create the gradient, and not the ones from the given view. This is because NativeScript provides us with the measured dimensions only late in the startup process (event after the AfterViewInit hook), which makes it difficult to synchronise the application of the gradient and the required bounds to display it. We don’t have this problem with Android because the implementation, because it doesn’t directly rely on the dimensions, but on the view itself.
In our use case, this isn’t a problem since we’re using it as a global background anyway, but it might be one if you plan to reuse this directive to fill only a portion of the screen.
Let’s reference the Directive within the
Now we can use the Directive to create the gradient with any number of colors that we want (try to add a third one!):
Our screen should now look like this:
That’s it ! I hope you found this tutorial useful, and if it’s the case, go ahead and share it 🙂
Don’t hesitate to write down a comment if you have any trouble.