Convert Custom Ionic 3 Transitions to Ionic 4
Support for custom transitions between pages in Ionic framework (e.g. when opening a modal page) has never been well documented. In Ionic 3, the enterAnimation
and leaveAnimation
options for modal haven't been documented at all. In Ionic 4, the documentation at least mentions them, although it doesn't provide much more than the type of the function to set them to.
Fortunately, there are blog posts for both Ionic 3 and Ionic 4 which provide more information and can serve as a good starting point for creating your own custom transitions. But even with all that, it can be tricky to convert existing custom Ionic 3 transitions to Ionic 4 when upgrading an application.
In this post I'm going to document the steps needed using the example transition from the Ionic 3 blog post mentioned above:
import { Animation, PageTransition } from 'ionic-angular';
export class ModalTranslateLeaveTransition extends PageTransition {
public init() {
const ele = this.leavingView.pageRef().nativeElement;
const wrapper = new Animation(
this.plt,
ele.querySelector('.modal-wrapper')
);
const contentWrapper = new Animation(
this.plt,
ele.querySelector('.wrapper')
);
wrapper.beforeStyles({ transform: 'translateX(100%)', opacity: 1 });
wrapper.fromTo('transform', 'translateX(0)', 'translateX(100%)');
wrapper.fromTo('opacity', 1, 1);
contentWrapper.fromTo('opacity', 1, 0);
this.element(this.leavingView.pageRef())
.duration(500)
.easing('cubic-bezier(.1, .7, .1, 1)')
.add(contentWrapper)
.add(wrapper);
}
}
In Ionic 4, transitions are implemented as simple functions instead of classes. This is a good starting point:
import { Animation } from '@ionic/core'; export function modalTranslateLeaveTransition( AnimationC: Animation, ele: HTMLElement ): Promise<Animation> { const baseAnimation = new AnimationC(); return Promise.resolve(baseAnimation.addElement(ele)); }
The name of the second parameter intentionally matches the name of the variable declared in the first line of Ionic 3 code because the value of the two is the same. It is used when querying HTML elements to create animations for. These are now passed into the animation using the
addElement
method instead of the constructor. This is how the code changes from Ionic 3 to Ionic 4 because of that:// Ionic 3 const wrapper = new Animation(this.plt, ele.querySelector('.modal-wrapper')); const contentWrapper = new Animation( this.plt, ele.querySelector('.wrapper') ); // Ionic 4 const wrapper = new AnimationC(); wrapper.addElement(ele.querySelector('.modal-wrapper')); const contentWrapper = new AnimationC(); wrapper.addElement(ele.querySelector('.wrapper'));
The methods for specifying the transition details (
beforeStyles
,fromTo
, etc.) have remained unchanged. The only remaining difference is how the final composite transition is constructed and returned. In Ionic 4, thebaseAnimation
created in the first step is used for that:return Promise.resolve( baseAnimation .addElement(ele) .duration(500) .easing('cubic-bezier(.1, .7, .1, 1)') .add(contentWrapper) .add(wrapper) );
Taking all this into account, this would be the final Ionic 4 transition converted from the initial Ionic 3 code:
import { Animation } from '@ionic/core';
export function modalTranslateLeaveTransition(
AnimationC: Animation,
ele: HTMLElement
): Promise<Animation> {
const baseAnimation = new AnimationC();
const wrapper = new AnimationC();
wrapper.addElement(ele.querySelector('.modal-wrapper'));
wrapper.beforeStyles({ transform: 'translateX(100%)', opacity: 1 });
wrapper.fromTo('transform', 'translateX(0)', 'translateX(100%)');
wrapper.fromTo('opacity', 1, 1);
const contentWrapper = new AnimationC();
wrapper.addElement(ele.querySelector('.wrapper'));
contentWrapper.fromTo('opacity', 1, 0);
return Promise.resolve(
baseAnimation
.addElement(ele)
.duration(500)
.easing('cubic-bezier(.1, .7, .1, 1)')
.add(contentWrapper)
.add(wrapper)
);
}
There's one more difference between Ionic 3 and Ionic 4 that's worth mentioning. The transition functions can be directly passed into the modal options. There's no need for registering them first in the AppModule
to assign string
keys to them:
const modal = await this.modalCtrl.create({
component: ModalPage,
enterAnimation: modalTranslateEnterTransition,
leaveAnimation: modalTranslateLeaveTransition
});
Although the conversion task might seem difficult at first, there aren't all that many changes and the process is quite straightforward.