4

When navigating to a new screen by calling NavController.navigateForward('/url') you get a free native animation which slides the screen in to view. This works as expected unless I use a component within a page component. When I do that, everything animates as expected except the component within the page.

When the following page is navigated to the content and title all slide into view as expected.

<ion-header>
    <h1>The Title</h1>
</ion-header>
<ion-content>
    Some content...
</ion-content>

However, if I extract the h1 tag to a component only the "Some content..." slides into view. "The Title" is displayed with no animation.

<ion-header>
    <app-my-component>The Title</app-my-component>
</ion-header>
<ion-content>
    Some content...
</ion-content>
Craig
  • 6,869
  • 3
  • 32
  • 52

2 Answers2

5

The reason why that's happening is because Ionic expects the ion-title to be in a certain place for it to be animated. You can see that by inspecting the the source code of the iOS page transition.

As you can see here Ionic gets the entering ion-toolbar like this:

const enteringToolBarEls = enteringEl.querySelectorAll(':scope > ion-header > ion-toolbar');

And here it gets the ion-title like this:

enteringTitle.addElement(enteringToolBarEl.querySelector('ion-title'));

That won't work since the structure of the HTML code will be different if you use a custom component in your ion-header:

ion-header > your-component > ion-toolbar

It's recommended not to use a custom component in the ion-header because Ionic expects it to be in a specific way in order to animate it properly.


That being said, if you really need to use a custom component there, you can crate your own custom page transition like this:

  1. Create a new file myAwesomeTransitionAnimation.ts with the content of the source code of the iOS page transition.
  2. Edit the code to make the transition work with your specific HTML structure
  3. Edit the app.module.ts file to use that transition instead of the default:
imports: [
    ...
    IonicModule.forRoot({  
      navAnimation: myAwesomeTransitionAnimation,
    }), 
  ],

Please keep in mind that doing so would override the default "animation" of all ion-nav and ion-router-outlet across the whole application.

If you just want to override it for iOS (using the default for Android), please take a look at this comment:

let ionic = [
  IonicModule.forRoot()
];

const platform = new Platform();

if (platform.is('ios')) {
  ionic = [
    IonicModule.forRoot({
      navAnimation: myAwesomeTransitionAnimation,
    })
  ]
}

And in module imports:

imports: [ ...ionic, ]
sebaferreras
  • 44,206
  • 11
  • 116
  • 134
  • 1
    Thank you for providing such a well articulated answer. Newbie alert; I just started working with ionic and angular a couple weeks ago. When I attempted to trace back through the SC starting at navigateForward I did not land in iosTransitionAnimation as you did which led to you being able to identify the root of the problem. Assuming I missing some fundamentals and need to read up on something...how did you go about tracing back to iosTransitionAnimation? – Craig May 17 '19 at 12:19
  • 1
    @Craig Glad to hear that it helped :) Well actually two years ago I was investigating [this issue using Ionic 2](https://stackoverflow.com/questions/35936198/ionic-2-global-navbar-for-the-app/37808988#37808988) when Mark Hartington (from Ionic team) wrote a comment pointing us in the right direction. Since that day I really enjoy reading the source code of Ionic to know how things work behind the scenes and to learn how to create new features following their recommended practices. – sebaferreras May 17 '19 at 12:39
  • 1
    Thanks! Addtion to, posting(https://www.damirscorner.com/blog/posts/20200501-CustomizingPageTransitionsInIonic5.html) was helpful. – junho Feb 23 '22 at 08:19
0

I know this question is quite old but I'd like to share another simple and really useful solution I found specifically using an Angular feature: "ViewContainerRef" (credit to this answer for the approach).

In the page .html:

<ion-header>
  <my-toolbar></my-toolbar>
</ion-header>

.html:

<ng-template #template>
  <ion-toolbar>
    <ion-title>Example</ion-title>
  </ion-toolbar>
</ng-template>

.ts:

@ViewChild('template', { static: true }) template;


constructor(
  private viewContainerRef: ViewContainerRef
) { }

ngOnInit() {
  this.viewContainerRef.createEmbeddedView(this.template);
}

This allows the ion-toolbar to be embedded directly in the ion-header instead of wrapped by the obscuring my-toolbar element, and avoid having to fix the transition issue at all.

Hope this helps anyone else stumbling across this in 2023!