Customizing Page Transitions in Ionic 5
Although Ionic supports custom transitions when navigating between pages, I couldn't find much documentation about it. However, by combining information from different sources I managed to create one and fully understand the code involved.
The default page transition can be easily replaced through Ionic Config. The custom animation can be specified as a value for the navAnimation
field:
@NgModule({
// ...
imports: [
BrowserModule,
IonicModule.forRoot({ navAnimation: pageTransition }),
AppRoutingModule
],
// ...
})
export class AppModule {}
This bit is documented but the documentation doesn't explain what should be passed as the value. The best starting points are the default Android and iOS page transitions. The value expected by the navAnimation
field is the animation factory function with the following signature:
function pageTransition(_: HTMLElement, opts: TransitionOptions): Animation;
Since Ionic doesn't seem to export the TransitionOptions
in the signature above, you'll need to copy it into your application from Ionic source code:
export interface TransitionOptions extends NavOptions {
progressCallback?: ((ani: Animation | undefined) => void);
baseEl: any;
enteringEl: HTMLElement;
leavingEl: HTMLElement | undefined;
}
The same goes for the getIonPageElement()
helper function that's used in both Android and iOS default page transitions:
export const getIonPageElement = (element: HTMLElement) => {
if (element.classList.contains('ion-page')) {
return element;
}
const ionPage = element.querySelector(
':scope > .ion-page, :scope > ion-nav, :scope > ion-tabs'
);
if (ionPage) {
return ionPage;
}
// idk, return the original element so at least something animates
// and we don't have a null pointer
return element;
};
Since the default Android page transition is much simpler from the iOS one, I based my custom page transition on its source code. After some refactoring, I came up with the following well-structured function (inline comments explain what individual parts do) which allows for easy modifications to the transition animation:
export function pageTransition(_: HTMLElement, opts: TransitionOptions) {
const DURATION = 300;
// root animation with common setup for the whole transition
const rootTransition = createAnimation()
.duration(opts.duration || DURATION)
.easing('cubic-bezier(0.3,0,0.66,1)');
// ensure that the entering page is visible from the start of the transition
const enteringPage = createAnimation()
.addElement(getIonPageElement(opts.enteringEl))
.beforeRemoveClass('ion-page-invisible');
// create animation for the leaving page
const leavingPage = createAnimation().addElement(
getIonPageElement(opts.leavingEl)
);
// actual customized animation
if (opts.direction === 'forward') {
enteringPage.fromTo('transform', 'translateX(100%)', 'translateX(0)');
leavingPage.fromTo('opacity', '1', '0.25');
} else {
leavingPage.fromTo('transform', 'translateX(0)', 'translateX(100%)');
enteringPage.fromTo('opacity', '0.25', '1');
}
// include animations for both pages into the root animation
rootTransition.addAnimation(enteringPage);
rootTransition.addAnimation(leavingPage);
return rootTransition;
}
The code uses the new Ionic Animations API which was recently officially announced. That's the main reason why it only works with Ionic 5.
However, the same APIs were already used internally in Ionic 4. If you haven't upgraded to Ionic 5 yet, you should still be able to use the above code with only minor modifications. To see what's different, you can check the source code for the default animations in the version of Ionic you're using.
The full source code for the sample project is available in a Bitbucket repository.
This blog post is a part of a series of posts about animations in Ionic.