Adding custom transitions/custom modal transition

Hey everyone,

I am looking for a way to add a custom modal transition. I’d like to have certain modals (not all modals) to be the full width of the viewport and slide up from the bottom, taking only 50% of the vertical viewport.

I believe to achieve this, I need to create a new transition and register it by injecting the Config and then doing config.setTransition('custom-transition', CustomTransition) however setTransition is private. Why is this?

How do I go about animating a modal to slide up? I’ve tried using .pageRef() and adding a custom class to the modal-wrapper to set the modal to full width, etc… I did get partially what I wanted, but the transitions weren’t desirable. It was animating from the center to the bottom half the screen.

Anyone have any ideas?

Thanks!

5 Likes

Yes, i wish too. I need slide up and down!

@ccdex_chris @badpenguin I just created 2 custom transitions for my modals and it works like a charm.

First, you need to create your transition classes.

scale-up-enter.transition.ts

import { Animation, PageTransition } from 'ionic-angular';

export class ModalScaleUpEnterTransition extends PageTransition {

public init() {
    const ele = this.enteringView.pageRef().nativeElement;
    const wrapper = new Animation(this.plt, ele.querySelector('.modal-wrapper'));

    wrapper.beforeStyles({ 'transform': 'scale(0)', 'opacity': 1 });
    wrapper.fromTo('transform', 'scale(0)', 'scale(1.0)');
    wrapper.fromTo('opacity', 1, 1);

    this
        .element(this.enteringView.pageRef())
        .duration(500)
        .easing('cubic-bezier(.1, .7, .1, 1)')
        .add(wrapper);
}
}

scale-up-leave.transition.ts - I want to point leavingView/enteringView difference out here.

import { Animation, PageTransition } from 'ionic-angular';

export class ModalScaleUpLeaveTransition 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': 'scale(0)', 'opacity': 1 });
    wrapper.fromTo('transform', 'scale(1)', 'scale(5.0)');
    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);
}
}

Then introduce your transition classes to ionic, by using Config. I did it on AppModule but you can basically do it anywhere.

app.module.ts

import { Config } from 'ionic-angular';

export class AppModule {
    constructor(public config: Config) {
        this.setCustomTransitions();
    }

    private setCustomTransitions() {
        this.config.setTransition('modal-scale-up-leave', ModalScaleUpLeaveTransition);
        this.config.setTransition('modal-scale-up-enter', ModalScaleUpEnterTransition);
    }
}

FInally set the transition name that you introduced to your modal definition.

your-page.component.ts

public presentYourModal() {
    const yourModal = this.modalController.create(YourModalComponent, { userId: 46 }, {
        showBackdrop: false,
        enableBackdropDismiss: false,
        enterAnimation: 'modal-scale-up-enter',
        leaveAnimation: 'modal-scale-up-leave'
    });
    yourModal.present();
}

That’s it!

It’s a pity that I had to go through ionic’s implementation of basic 2 transitions to understand how this works. Even enterAnimation and leaveAnimation options are not visible for modalOptions doc on ionic site. A final note for the internet: by the time I’m writing this, it’s ionic 3 and angular 4.

16 Likes

Definitely going to try this. Thanks so much for sharing @onderceylan!

1 Like

Is it works? Anybody check it? It’s not working for me? My ionic version is 3.0.1

What’s not working exactly?

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { ErrorHandler, NgModule } from '@angular/core';
import { Config, IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { ModalScaleUpEnterTransition } from '../classes/scale-up-enter.transition';
import { ModalScaleUpLeaveTransition } from '../classes/scale-up-leave.transition';

import { MyApp } from './app.component';

import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';

@NgModule({
  declarations: [
    MyApp,
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    IonicModule.forRoot(MyApp),
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
  ],
  providers: [
    StatusBar,
    SplashScreen,
    { provide: ErrorHandler, useClass: IonicErrorHandler }
  ]
})
export class AppModule {
  constructor(public config: Config) {
    this.setCustomTransitions();
  }

  private setCustomTransitions() {
    this.config.setTransition('modal-scale-up-leave', ModalScaleUpLeaveTransition);
    this.config.setTransition('modal-scale-up-enter', ModalScaleUpEnterTransition);
  }
}

example page

import { Component, ViewChild, trigger, state, style, transition, animate, keyframes } from '@angular/core';
import { IonicPage, NavController, NavParams, AlertController, ModalController, Slides } from 'ionic-angular';

@IonicPage()
@Component({
  selector: 'page-intro',
  templateUrl: 'intro.html',
})
export class Intro {
  @ViewChild(Slides) slides: Slides;
  sliderOptions: any = {
    effect: 'cube',
    noSwiping: true,
    direction: 'vertical'
  };
  constructor(public navCtrl: NavController, public navParams: NavParams, private alertCtrl: AlertController, public modalCtrl: ModalController) {

  }

  ionViewDidLoad() {
    console.log('ionViewDidLoad Intro');
  }

  openLoginModal() {
    let loginModal = this.modalCtrl.create('LoginModal', {
      enterAnimation: 'modal-scale-up-enter',
      leaveAnimation: 'modal-scale-up-leave'
    });
    loginModal.onDidDismiss(data => {
      console.log(data);
    });
    loginModal.present();
  }
}

It should work? I added custom console.log message in ModalScaleUpEnterTransition but it doesn’t show up when entering a modal.

Yeah it should work, you may have a styling issue. I can’t really say much without further inspection. Maybe a plunker?

The solution provided by @onderceylan works very well. I tested with Ionic 3 in the iOS simulator.

Small question: how to dismiss the view, when I use
this.viewCtrl.dismiss();
it doesn’t have any animation at all

@dranix I’m doing the same and it works fine for me. It sounds like your leaveAnimation doesn’t work as expected. Did you pay attention on leavingView? Debugging on your leave transition class would help.

@onderceylan you’re right. It works perfectly. Thank a bunch :smiley:

1 Like

Should be set ‘enterAnimation’ in 3rd parameter:

let loginModal = this.modalCtrl.create(‘LoginModal’, {}, {
enterAnimation: ‘modal-scale-up-enter’,
leaveAnimation: ‘modal-scale-up-leave’
});

  1. “super.init();” should run in first line of each transition’s init, or the modal content may in wrong position.
public init() {
   super.init(); //<--- add this

  1. Custom transition don’t support the default option “showBackdrop: false”. Backdrop will always show.

Checked “Backdrop” show/hide logic is on the template, not one the code:

Any idea how to fix?

Hi, can you help me out… how to change your code so that the animation slides from right to left like a sliding menu ?

Hey, you can inspect ionic’s source code. There’s those animations as far as I know.

Hello guys, on the same topic here.
I am using this.view.dismiss() on a page which is not a modal, and it closes with slide-to-right transition for me.
I how can i make the default slide-to-bottom, on this.view.dimiss(). I see that you mentioned above on leaveAnimation, but i am not sure how to make it out.

I was having a weird issue with the screen popping on dismiss. I changed a line on the scale-up.leave.transition.ts to fix this.

wrapper.fromTo('transform', 'scale(1)', 'scale(5.0)');

to

wrapper.fromTo('transform', 'scale(1)', 'scale(0)');

It started performing as expected.

Hope this helps someone!

3 Likes

Thank you, I was able to change popover transition using your instructions. Except popover does not have options to change transitions per instance, so you need to set it globally for whole app in config.

Maybe this can help for those who wants to set transition for all modals, or popovers… etc
Here is how you can set transitions:

I have just used

	popoverEnter: 'custom-popover-pop-in',
      	popoverLeave: 'custom-popover-pop-out',

where

  this.config.setTransition('custom-popover-pop-in', CustomPopoverPopIn )
  this.config.setTransition('custom-popover-pop-out', CustomPopoverPopOut )

same as @onderceylan described for modal transitions

Happy coding :wink:

and the backdrop? i’m using modal with custom width… so, the backdrop don’t follows the same effect… how can i add him?

Thanks a lot, you helped me for sure!! :hugs: