The Ionic Framework animations are choppy at best, they will work almost perfectly on stronger devices, but God forbid using them on anything slower. Don’t get me wrong, I still believe Ionic is currently the best solution for hybrid mobile development. Still, those animations are a hard pill to swallow.
 
To make a story short, yesterday morning I found a possible solution to this problem. It’s a Telerik (KendoUI owner) Cordova plugin made to mimics native page (or view in our case) animations. One thing caught my eyes, it was also supposed to be platform agnostic. Whaaaaat, how?
 
Now comes the funny part, the solution is so stupidly simple that I had to laugh. It goes like this. No matter what framework is used, before a transition can occur, the plugin will take a screenshot of your current state. It will then overlay it on top of your view simulating native page transition. And it truly works.
 
 

Note: If this tutorial was helpful, need further clarification, something is not working or do you have a request for another Ionic post? Furthermore, if you don't like something about this blog, if something is bugging you, don't like how I'm doing stuff here, again leave me a comment below. I'm here to help you, I expect the same from you. Feel free to comment below, subscribe to my blog, mail me to dragan.gaic@gmail.com, or follow and mention me on twitter (@gajotres). Thanks and have a nice day!

PS. If you want my help, if possible (even if it takes you some time to do that), create a working example I can play with. Use Plunker for AngularJS based questions or jsFiddle for jQuery/jQuery Mobile based questions.


 

Table of Contents

 
Click here if you want to see other tutorials, or articles about the Ionic framework (themes, templates, plugins, tutorials)
 

Introduction

Seeing is believing:
 

Default CSS Transition Animations:




Native Transition Animations:




Note: These were recorded on Sony M4; a shi**y smartphone just to make this difference more emphasized.
 


Installation

Update: 28.1.2016: I've updated this article with better instructions
 
Follow the instructions below to create a project folder; including all required files. Then download the GitHub repo from the last page and copy www folder to a newly created project; or follow GitHub repo instructions.
 

1. Update Ionic & Cordova

 
You need to have a latest nodeJS version, without it, you’ll not be able to install/update Cordova and Ionic appropriately.
 
If you have a previous Ionic/Cordova installation make sure its up to date, older versions may not work with this tutorial. Though latest versions may also mess things up:
 
npm install -g cordova ionic
 
or you can even do it like this:
 
npm update -g cordova ionic
 

2. Create a Project

 
Create a new project:
 
ionic start IonicTransitionDemo blank
cd IonicTransitionDemo
 
Warning: Since some of you never worked with Ionic CLI. From this point and further, every time I tell you to execute something, do that inside a project folder.
 

3. Add Required Platform

 
Add Android platform:
 
ionic platform add android
 
MacOS users can also add iOS platform:
 
ionic platform add ios
 

4. Install Cordova Plugins:

 
Plugin download and documentation:
 
Plugin + Docs
 
 
Now let’s install the Telerik Native Page Transitions Plugin:
 
cordova plugin add https://github.com/Telerik-Verified-Plugins/NativePageTransitions
 
If you’re using Cordova 4+ don’t forget to install Cordova Whitelist plugin:
 
cordova plugin add cordova-plugin-whitelist
 
Add this complementary security meta tag to your index.html file:
 
<meta http-equiv="Content-Security-Policy" content="default-src *; script-src 'self' 'unsafe-inline' 'unsafe-eval' *; style-src  'self' 'unsafe-inline' *">
 

Preparation

Good news, there’s nothing to inject, nothing to initialize.
 
We can configure this plugin on a global level, thus saving us some space:
 
nameApp.run(function($ionicPlatform) {
    $ionicPlatform.ready(function() {

		// then override any default you want
		window.plugins.nativepagetransitions.globalOptions.duration = 500;
		window.plugins.nativepagetransitions.globalOptions.iosdelay = 350;
		window.plugins.nativepagetransitions.globalOptions.androiddelay = 350;
		window.plugins.nativepagetransitions.globalOptions.winphonedelay = 350;
		window.plugins.nativepagetransitions.globalOptions.slowdownfactor = 4;
		// these are used for slide left/right only currently
		window.plugins.nativepagetransitions.globalOptions.fixedPixelsTop = 0;
		window.plugins.nativepagetransitions.globalOptions.fixedPixelsBottom = 0;
	
    });
}); 
 
By default, this plugin can be used programmatically and with a custom anchor tag. Unfortunately, only the first solution works correctly with Ionic. Anchor tag approach is choppy for some reason.
 
This is how you can do that programmatically, just be warned that page transition must be initialized before the plugin:
 
$state.go('view', {movieid: id});	
window.plugins.nativepagetransitions.slide(
  {"direction":"up"},
  function (msg) {console.log("success: " + msg)}, // called when the animation has finished
  function (msg) {alert("error: " + msg)} // called in case you pass in weird values
);
 
Some of you may not like this approach so I found time to create a directive that can be used on any tag you like, as long as it can initiate a transition:
 
nameApp.directive('goNative', ['$ionicGesture', '$ionicPlatform', function($ionicGesture, $ionicPlatform) {
  return {
    restrict: 'A',

    link: function(scope, element, attrs) {

      $ionicGesture.on('tap', function(e) {

        var direction = attrs.direction;
        var transitiontype = attrs.transitiontype;

        $ionicPlatform.ready(function() {

          switch (transitiontype) {
            case "slide":
              window.plugins.nativepagetransitions.slide({
                  "direction": direction
                },
                function(msg) {
                  console.log("success: " + msg)
                },
                function(msg) {
                  alert("error: " + msg)
                }
              );
              break;
            case "flip":
              window.plugins.nativepagetransitions.flip({
                  "direction": direction
                },
                function(msg) {
                  console.log("success: " + msg)
                },
                function(msg) {
                  alert("error: " + msg)
                }
              );
              break;
			  
            case "fade":
              window.plugins.nativepagetransitions.fade({
                  
                },
                function(msg) {
                  console.log("success: " + msg)
                },
                function(msg) {
                  alert("error: " + msg)
                }
              );
              break;

            case "drawer":
              window.plugins.nativepagetransitions.drawer({
				  "origin"         : direction,
				  "action"         : "open"
                },
                function(msg) {
                  console.log("success: " + msg)
                },
                function(msg) {
                  alert("error: " + msg)
                }
              );
              break;
			  
            case "curl":
              window.plugins.nativepagetransitions.curl({
				  "direction": direction
                },
                function(msg) {
                  console.log("success: " + msg)
                },
                function(msg) {
                  alert("error: " + msg)
                }
              );
              break;			  
			  
            default:
              window.plugins.nativepagetransitions.slide({
                  "direction": direction
                },
                function(msg) {
                  console.log("success: " + msg)
                },
                function(msg) {
                  alert("error: " + msg)
                }
              );
          }


        });
      }, element);
    }
  };
}]);
 
It can be used like this:
 
<ion-item item="group" collection-repeat="movie in movies" collection-item-width="'100%'" collection-item-height="100" href="#/movie/{{movie.id}}" class="item-thumbnail-left" transitiontype="flip" direction="left" go-native>
 
or even like this:
 
  <ion-nav-bar class="bar-positive">
    <ion-nav-back-button class="button-clear" transitiontype="flip" direction="right" go-native>
      <i class="ion-arrow-left-c"></i> Back
    </ion-nav-back-button>
  </ion-nav-bar>  
 
If you prefer to do it programmatically, use it something like this:
 
nameApp.service('Navigation', function($state) {
  //directly binding events to this context
  this.goNative = function(view, data, direction) {
    $state.go(view, data);
    window.plugins.nativepagetransitions.slide({
        "direction": direction
      },
      function(msg) {
        console.log("success: " + msg)
      }, // called when the animation has finished
      function(msg) {
        alert("error: " + msg)
      } // called in case you pass in weird values
    );
  };
});
 
Last but not least, we need to turn off Ionic view animations, they may interfere with this plugin:
 
nameApp.config(function($stateProvider, $urlRouterProvider, $ionicConfigProvider) {
 
  $ionicConfigProvider.views.transition('none');
 

Code

This is our final code:
 

HTML

<!DOCTYPE html>
<html ng-app="starter">
  <head>
    <meta charset="utf-8">
	<meta http-equiv="Content-Security-Policy" content="default-src *; script-src &apos;self&apos; &apos;unsafe-inline&apos; &apos;unsafe-eval&apos; *; style-src  &apos;self&apos; &apos;unsafe-inline&apos; *">	
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
    <title></title>

    <link href="lib/ionic/css/ionic.css" rel="stylesheet">
    <link href="css/style.css" rel="stylesheet">

    <!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
    <link href="css/ionic.app.css" rel="stylesheet">
    -->

    <!-- ionic/angularjs js -->
    <script src="lib/ionic/js/ionic.bundle.js"></script>
	
    <!-- cordova script (this will be a 404 during development) -->
    <script src="cordova.js"></script>
	
    <!-- your app's js -->
    <script src="js/app.js"></script>
  </head>
  <body>
  
  <!-- The nav bar that will be updated as we navigate -->
  <ion-nav-bar class="bar-positive">
    <ion-nav-back-button class="button-clear" transitiontype="flip" direction="right" go-native>
      <i class="ion-arrow-left-c"></i> Back
    </ion-nav-back-button>
  </ion-nav-bar>  
  
  <ion-nav-view></ion-nav-view>
		  <!-- ng-click="changePage(movie.id)" -->  
  <script id="list.html" type="text/ng-template">
    <ion-view view-title="Search The Movie Database"> 
      <ion-content>
        <label class="item item-input">
          <i class="icon ion-search placeholder-icon"></i>
          <input type="search" placeholder="Search" ng-model="movie.name" ng-change="searchMovieDB()">
        </label>

          <ion-list can-swipe="true">
          	<ion-item item="group" collection-repeat="movie in movies" collection-item-width="'100%'" collection-item-height="100" href="#/movie/{{movie.id}}" class="item-thumbnail-left" transitiontype="flip" direction="left" go-native>
          		<img ng-src="https://image.tmdb.org/t/p/w92{{movie.poster_path}}" onerror="this.src = 'https://www.ginesisnatural.com/images/no_image.jpg';">
          		<h2>{{movie.original_title}}</h2>
          		<h4>{{movie.release_date}}</h4>
          		<ion-option-button class="button-light icon ion-edit">Edit</ion-option-button>
          		<ion-option-button class="button-assertive icon ion-trash-a">Share</ion-option-button>
          	</ion-item>
          </ion-list>
      </ion-content>
    </ion-view>    
  </script>  
  
  <script id="view.html" type="text/ng-template">
    <ion-view view-title="Movie details">   
      <ion-content>
        <div class="list card">
  
          <div class="item item-avatar">
            <img src="http://files.softicons.com/download/object-icons/movies-icons-by-pinchodesigns/png/32x32/Movie.png">
            <h2>{{movie.original_title}}</h2>
            <p>{{movie.release_date}}</p>
          </div>
  
          <div class="item item-image">
            <img ng-src="https://image.tmdb.org/t/p/w92{{movie.poster_path}}" width="200px" />
          </div>
  
          <a class="item" href="#">
              Average Vote: <strong>{{movie.vote_average}}</strong> (Votes: {{movie.vote_count}})
            </a>
  
        </div>
      </ion-content>
    </ion-view>     
  </script>   
  
  </body>
</html>
 
Continue to the next page

  • Wowww, you are the best! xD

    • Thank you 🙂

      • venkat

        I used above code it helps me more but when i click hardware backbutton transition effect is not working can any one help me

        • Anil Sharma

          same issue here, if i tap on back button on nav bar works as expected but hardware backbutton, view moves to left instead of right

          • Why don’t you just catch hardware back button and do everything from there, it’s not that hard.

  • Evandro Oliveira

    Awesome!! I’m facing a problem when deploying the app… When I test with live reload in my phone it works perfect!! But when I build my application without live reload “ionic run android” I get the error “Cannot read property nativepagetransitions of undefined”. It cannot find the property in “window.plugins.nativepagetransitions”….. any Idea? 😀

    • Try to remove the plugin then add it back again.

  • Krishnamoorthy Damodaran

    Nice work!!.. It is working perfect!.. Thanks for sharing.. Is there any way to apply native animation for sidemenu transition?

    • It could be possible with drawer native animation but that’s just a theory, I never tried it in a real life.

  • Mladen Petrovic

    Hey nice tutorial Dragan, it helped me because this plugin didn’t work for me until i added: $ionicConfigProvider.views.transition(‘none’);

  • Ahmed

    where do i have to add the first codes in preparation?

    • which one?

      • ahmed sunil

        i mean, how to call to that plugin from my index.html

        • I can’t help you without seeing your code. On the other hand, I gave you a working example in my article, use it to learn how to do exactly that.

  • Luís Cunha

    Hi,

    Thank you very much for this tutorial and for the directive, it really helped a lot =)

    I have one question though, I was unable to replace the default animations by simply adding the global overrides:

    .run(function($ionicPlatform) {
    $ionicPlatform.ready(function() {
    // then override any default you want
    window.plugins.nativepagetransitions.globalOptions.duration = 500;
    window.plugins.nativepagetransitions.globalOptions.iosdelay = 350;
    window.plugins.nativepagetransitions.globalOptions.androiddelay = 350;
    window.plugins.nativepagetransitions.globalOptions.winphonedelay = 350;
    window.plugins.nativepagetransitions.globalOptions.slowdownfactor = 4;
    // these are used for slide left/right only currently
    window.plugins.nativepagetransitions.globalOptions.fixedPixelsTop = 0;
    window.plugins.nativepagetransitions.globalOptions.fixedPixelsBottom = 0;
    });
    });

    I was only able to get the native animations by using your directive.
    So my question is, do the global overrides work on their own, or do is it not possible to globally enable them by default?
    Thanks.

    • Global overrides should work on their own. And what do you mean by “I was unable to replace the default animations by simply adding the global overrides”?

      • Luís Cunha

        I may be mistaken, but from what I understood, adding that .run function should automatically replace the default transition animations, or is this incorrect?
        What I was trying to achieve was for all the transition animations to be replaced by these native ones for the whole app without having to add parameters to the html, etc., is this possible using solely what the plugin provides?

        • Adding run function and changing global variables will affect all transitions. You still need to manually call a wanted transition method, for example: window.plugins.nativepagetransitions.fade will do a fade transition.

          • Luís Cunha

            Alright then, thanks for the explanation.

          • Luís Cunha

            Just as a quick clarification, I’m getting this message in the log:

            Probably running inside a companion app, your app may crash if your html file is not in the root!

            And I couldn’t figure out why. When is this triggered and why?

  • Saimonas

    Hello, with ionic, i see double effect, then i press “back” i see double animation, why? help 🙁

    • What kind of double effect and double animation?

      • Saimonas

        two times animations, slide

        • I think you need to play with configuration options (those found in the .run section). Every application is different in some way or another and requires a distinct set of configuration options.

          • Saimonas

            “slowdownfactor” what is this?

          • You should read the official documentation, I don’t remember any more.

          • Saimonas

            Check my problem watch?v=wY4wKXk3Po0

  • Is there a way to use it with $location.url() ?

  • Saimonas

    anyone know whats wrong for this plugin? watch?v=wY4wKXk3Po0

    • Liu Tsz Ki

      Hi Saimonas, I get the same issue as yours. Did you figure out what’s wrong?

  • Is possible close the side menu before start the native transition? 🙂

    • I think you should be able to do that. Just close it programmatically and trigger a native transition. You will probably need to tweak animation speed but it should work.

  • 文壮 刘

    Awesome, really beautiful and smooth animations. Thank you for nice tutorial series.

  • Saimonas

    this plugin has a lot bugs…

  • Arnold Tan

    i got this error when i run on browser “Cannot read property ‘nativepagetransitions’ of undefined”

    • Have you installed the plugin? Or if you did, uninstall it and add it again.

  • SUJITH

    i got this error “Uncaught TypeError: Cannot read property ‘nativepagetransitions’ of undefined”
    followed all the steps correctly but still unable to make it work.
    previousely worked like charm in ionic version 1.0.1 but when i updated to ionic version 1.1.1 ,not able to use this plugin. how do i make it work,help me

    • Remove plugin and add it again. This error means that plugin is not available, for whatever reason, reinstall is the best way to solve this problem.

      • SUJITH

        thankyou for your quick reply but i hav reinstalled 3 times but no luck 🙁

        • Can you create a new project? Use my example above with Ionic 1.1.1 and see if it’s working. If it works then problem is somewhere in your project. If it doesn’t work that problem is in Ionic 1.1.1.

          • CeebLaj Thoj

            The problem is the code in this sample doesn’t inject ‘ionic-native-transitions’ in angular.module(….)

          • This code does not require ionic-native-transitions because it’s not using that plugin, just read the article. This example was written before that plugin even existed and it works just fine.

  • Jonathan Chen

    This is really awesome! I’ve been looking for this solution for a long time. Thanks for sharing!

  • Aqeel Bhatt

    Awesome 🙂 Default CSS3 transitions are extremely choppy on Android, though they work seamlessly on iOS. I integrated this into my project. So far so good. Cheers!

  • Zoo Keeper

    This plugin simply does not work, Uncaught TypeError: Cannot read property ‘nativepagetransitions’ of undefined. Have removed and uninstalled it like 50 times.

    • This pluguin works just fine, I can tell you that.

      Tell me one thing, while creating your project, have you?:

      1. Add platform (Android/iOS) before this plugin?
      2. Add plugin before platform?

      • Zoo Keeper

        Yes i did all that but following the instructions i still couldn’t get it to work so i googled and found this on github: https://github.com/shprink/ionic-native-transitions. But even still following that too didn’t work then i read one of the posts under issues and found out that i have to include a ionic-native-transitions.min.js file in my index.html after doing that it worked just fine.

        • Funny, that file was not required when I was writing this article. I will need to check this out and update this article. Thanks for pointing this out.

  • CeebLaj Thoj

    Hi, I followed exactly the same code as your in ionic on Android work very well but on other side on IOS when I do ionic run ios or ionic emulate ios when the app opened I can’t navigate or touch on any button and I’ve got this message from XCode console log: THREAD WARNING: [‘NativePageTransitions’] took ‘13.799072’ ms. Plugin should use a background thread. , please help…!

    • Zarko Dencic

      Same problem here. Haven’t checked console, but I can’t navigate anywhere.

  • Raúl Alfaro

    Hi, thanks for the post 🙂

    Is this posible using PhonegapBuild?

  • feig

    Thanks for the summary, the animation is very beautiful.

  • Rahul Varadharajan

    i have downloaded the your source code from github. when run this i am getting the error in the browser console like this ” “uncaught TypeError: Cannot read property ‘nativepagetransitions’ of undefined” in lines “window.plugins.nativepagetransitions.globalOptions.duration = 500”.. can you tell me whats the issue

    • Yousuf Alvi

      Do you get the same error when you run your app on device ? I get the above error on my dev machine’s browser but no when I run the apk on device, It works perfectly fine then

    • guyromb

      It works only on mobile devices. Not on the browser. To avoid this error you can add:

      if(!window.plugins || !window.plugins.nativepagetransitions)
      return false;

  • Yousuf Alvi

    Is there a possibility to transit or animate only part of the view? For example I have an app with tabs. And I want tabs to and header to remain static only want the contents of each tab to slide or flip in or out ?

  • Michael Gustmann

    Can I use this to animate $ionicmodal transitions? I can’t figure out where to put the nativepagetransitions.

  • fire_crow

    when you onHold or long touch the item, the transition effectc loss !

  • mohammad raza

    Well Done. Nicely managed tutorial… Thanks

  • hva.narola

    Thanks for nice tutorial. But i have some issue with tabbar navigation view. Transition seems to be not working on tab icon click navigation. would you please provide some patch or hack for same.

  • What a great tutorial! a quick question. Is there a way to trigger one animation to the “BACK” of an specific view?
    So, for example I can go to myView with slide up and go back with slide down using the programatic way (without directive).

    Thanks

  • Thank you! I used this to change the animation of an specific view using the programatic way (window.plugins.nativepagetransitions.slide(…etc etc ).

    I just have one problem, the default animation (slide left) also happens when I enter the view, so I have something like a diagonal slide… is there a way to prevent this to to happen?