Ionic 离子自定义模态动画

ufj5ltwl  于 2022-12-09  发布在  Ionic
关注(0)|答案(6)|浏览(281)

Ionic模态自带标准动画slide-in-up,有没有可能把动画改成fade-in

fwzugrvs

fwzugrvs1#

为了给离子模态添加自定义过渡,我们将使用离子模态选项enterAnimationleaveAnimationfrom ModalOptions接口。对于模态,有过渡状态:在进入模态和离开模态时,当我们关闭它。如果你看离子模态选项界面,你会发现2个选项,以添加动画的两个状态。

export interface ModalOptions {
    showBackdrop?: boolean;
    enableBackdropDismiss?: boolean;
    enterAnimation?: string;
    leaveAnimation?: string;
    cssClass?: string;
}

我们将在modal中使用这些选项来指定我们使用来自ionic-angular的Animation类创建的过渡类。
创建2个过渡类,用于进入和离开:

输入转换时.转换.ts

import { Animation, PageTransition } from 'ionic-angular';
export class ModalTranslateEnterTransition extends PageTransition {
    public init() {
        const ele = this.enteringView.pageRef().nativeElement;
        const wrapper = new Animation(this.plt, ele.querySelector('.modal-wrapper'));
        wrapper.beforeStyles({ 'transform': 'translateX(100%);', 'opacity': 1 });
        wrapper.fromTo('transform', 'translateX(100%)', 'translateX(0)');
        wrapper.fromTo('opacity', 1, 1);
        this
            .element(this.enteringView.pageRef())
            .duration(500)
            .easing('cubic-bezier(.1, .7, .1, 1)')
            .add(wrapper);
    }
}

休假转换.转换.ts

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);
    }
}

然后在app.module.ts中导入这些模块

export class AppModule {
    constructor(public config: Config) {
        this.setCustomTransitions();
    }
    private setCustomTransitions() {
        this.config.setTransition('modal-translate-up-enter', ModalTranslateEnterTransition);
        this.config.setTransition('modal-translate-up-leave', ModalTranslateLeaveTransition);
    }
}

并使用以下选项创建模态:

var modal = this.modalCtrl.create(AddToCartModalPage, {
    productId: this.productId,
    skuId: this.skuId,
    zipcode: this.zipcode,
    sellerProfileId: this.sellerProfileId,
    branchId: this.branchId,
    changeSeller: this.changeSeller
}, {
    showBackdrop: false,
    enableBackdropDismiss: false,
    cssClass: 'add-to-cart-modal',
    enterAnimation: 'modal-translate-up-enter',
    leaveAnimation: 'modal-translate-up-leave'
});

查找更多信息我的文章在这里:Blog
在此处查找完整的演示存储库:Github

y3bcpkx1

y3bcpkx12#

您可以添加自己的动画css,例如:

.slide-in-right {
  -webkit-transform: translateX(100%);
    transform: translateX(100%); }

.slide-in-right.ng-enter, .slide-in-right > .ng-enter {
  -webkit-transition: all cubic-bezier(0.1, 0.7, 0.1, 1) 400ms;
  transition: all cubic-bezier(0.1, 0.7, 0.1, 1) 400ms; }

.slide-in-right.ng-enter-active, .slide-in-right > .ng-enter-active {
  -webkit-transform: translateX(0);
    transform: translateX(0); }

.slide-in-right.ng-leave, .slide-in-right > .ng-leave {
  -webkit-transition: all ease-in-out 250ms;
  transition: all ease-in-out 250ms; }

和用法
对于“淡入”也是如此
https://forum.ionicframework.com/t/slide-in-right-animation-for-ionicmodal/18882

hpxqektj

hpxqektj3#

几天前我在Angular 2上遇到了同样的问题。我是这样解决的:
我有两个不同的组件:

  • 导航栏组件(或任何用于单击并使离子模态出现的组件);在我例子中,它将是“nav-header.component.ts
  • 模态组件,在我的例子中是“modal-profile.component.ts

模态配置文件.组件.ts(模态配置文件组件类):

这里,您需要导入“ModalController”,然后需要将其自己的示例传递给ModalProfileComponent构造函数。

import { ModalController } from '@ionic/angular';

export class ModalProfileComponent {
  constructor( public modal: ModalController ) { }
}

此外,我还使用该类对模态(HTML和CSS)进行结构化和图形化编辑。

导航头.组件.ts(导航头组件类):

首先,导入AnimationControllerModalController和您在第一步中创建的模态类:

import { AnimationController } from '@ionic/angular';
import { ModalController } from '@ionic/angular';
import { ModalProfileComponent } from '../../home/components/modal-profile.component';

然后,加入下列执行严修做为建构函式参数:

constructor(private modal: ModalController, private animationCtrl: AnimationController) {}

现在,通过单击所需的HTML元素声明一个将调用的方法。我将使用onOptionsClick()
在此方法中,您现在可以使用离子模态函数enterAnimationleaveAnimation自定义打开和关闭时的模态行为。
您可以按照离子文档中的“模态”部分进行操作。
以下是我改进的解决方案:

async onOptionsClick() {

const enterAnimation = (baseEl: HTMLElement) => {
  const root = baseEl.shadowRoot;

  const backdropAnimation = this.animationCtrl.create()
    .addElement(root.querySelector('ion-backdrop')!)
    .fromTo('opacity', '0.01', 'var(--backdrop-opacity)');

  const wrapperAnimation = this.animationCtrl.create()
    .addElement(root.querySelector('.modal-wrapper')!)
    .fromTo('transform', 'translateY(-100%)', 'translateY(0)');

  return this.animationCtrl.create()
    .addElement(baseEl)
    .easing('ease-out')
    .duration(500)
    .addAnimation([backdropAnimation, wrapperAnimation]);
}

const leaveAnimation = (baseEl: HTMLElement) => {
  return enterAnimation(baseEl).direction('reverse');
}

const modal = await this.modal.create({
  component: ModalProfileComponent,
  enterAnimation,
  leaveAnimation
});
modal.present();

}
希望你觉得有用!:)

uqxowvwt

uqxowvwt4#

no ionic不提供淡入动画。但您可以使用animate.css来实现这一点

6jygbczu

6jygbczu5#

您可以使用以下开源代码中的现成动画:
Ionic v3 here的模态/弹出过渡类

iq3niunx

iq3niunx6#

import { AnimationController } from '@ionic/angular';
export const SwipeToCloseDefaults = {
    MIN_PRESENTING_SCALE: 0.93,
  };
export const enterFromRightAnimation = (baseEl, presentingEl) => {
    const backdropAnimation = new AnimationController().create()
      .addElement(baseEl.querySelector('ion-backdrop'))
      .fromTo('opacity', 0.01, 'var(--backdrop-opacity)')
      .beforeStyles({
      'pointer-events': 'none'
    })
      .afterClearStyles(['pointer-events']);
    const wrapperAnimation = new AnimationController().create()
      .addElement(baseEl.querySelectorAll('.modal-wrapper, .modal-shadow'))
      .beforeStyles({ 'opacity': 1 })
      .fromTo('transform', 'translateX(100vh)', 'translateX(0vh)');
    const baseAnimation = new AnimationController().create()
      .addElement(baseEl)
      .easing('cubic-bezier(0.32,0.72,0,1)')
      .duration(500)
      .addAnimation(wrapperAnimation);
    if (presentingEl) {
      const isMobile = window.innerWidth < 768;
      const hasCardModal = (presentingEl.tagName === 'ION-MODAL' && presentingEl.presentingElement !== undefined);
      const presentingAnimation = new AnimationController().create()
        .beforeStyles({
        'transform': 'translateX(0)',
        'transform-origin': 'top center',
        'overflow': 'hidden'
      });
      const bodyEl = document.body;
      if (isMobile) {
        /**
         * Fallback for browsers that does not support `max()` (ex: Firefox)
         * No need to worry about statusbar padding since engines like Gecko
         * are not used as the engine for standlone Cordova/Capacitor apps
         */
        const transformOffset = (!CSS.supports('width', 'max(0px, 1px)')) ? '30px' : 'max(30px, var(--ion-safe-area-top))';
        const modalTransform = hasCardModal ? '-10px' : transformOffset;
        const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
        const finalTransform = `translateX(${modalTransform}) scale(${toPresentingScale})`;
        presentingAnimation
          .afterStyles({
          'transform': finalTransform
        })
          .beforeAddWrite(() => bodyEl.style.setProperty('background-color', 'black'))
          .addElement(presentingEl)
          .keyframes([
          { offset: 0, filter: 'contrast(1)', transform: 'translateX(0px) scale(1)', borderRadius: '0px' },
          { offset: 1, filter: 'contrast(0.85)', transform: finalTransform, borderRadius: '10px 10px 0 0' }
        ]);
        baseAnimation.addAnimation(presentingAnimation);
      }
      else {
        baseAnimation.addAnimation(backdropAnimation);
        if (!hasCardModal) {
          wrapperAnimation.fromTo('opacity', '0', '1');
        }
        else {
          const toPresentingScale = (hasCardModal) ? SwipeToCloseDefaults.MIN_PRESENTING_SCALE : 1;
          const finalTransform = `translateX(-10px) scale(${toPresentingScale})`;
          presentingAnimation
            .afterStyles({
            'transform': finalTransform
          })
            .addElement(presentingEl.querySelector('.modal-wrapper'))
            .keyframes([
            { offset: 0, filter: 'contrast(1)', transform: 'translateX(0) scale(1)' },
            { offset: 1, filter: 'contrast(0.85)', transform: finalTransform }
          ]);
          const shadowAnimation =new AnimationController().create()
            .afterStyles({
            'transform': finalTransform
          })
            .addElement(presentingEl.querySelector('.modal-shadow'))
            .keyframes([
            { offset: 0, opacity: '1', transform: 'translateX(0) scale(1)' },
            { offset: 1, opacity: '0', transform: finalTransform }
          ]);
          baseAnimation.addAnimation([presentingAnimation, shadowAnimation]);
        }
      }
    }
    else {
      baseAnimation.addAnimation(backdropAnimation);
    }
    return baseAnimation;
  };
  

export const leaveToRightAnimation =  (baseEl, presentingEl, duration = 500) => {
    const backdropAnimation = new AnimationController().create()
      .addElement(baseEl.querySelector('ion-backdrop'))
      .fromTo('opacity', 'var(--backdrop-opacity)', 0.0);
    const wrapperAnimation = new AnimationController().create()
      .addElement(baseEl.querySelectorAll('.modal-wrapper, .modal-shadow'))
      .beforeStyles({ 'opacity': 1 })
      .fromTo('transform', 'translateX(0vh)', 'translateX(100vh)');
    const baseAnimation = new AnimationController().create()
      .addElement(baseEl)
      .easing('cubic-bezier(0.32,0.72,0,1)')
      .duration(duration)
      .addAnimation(wrapperAnimation);
    if (presentingEl) {
      const isMobile = window.innerWidth < 768;
      const hasCardModal = (presentingEl.tagName === 'ION-MODAL' && presentingEl.presentingElement !== undefined);
      const presentingAnimation = new AnimationController().create()
        .beforeClearStyles(['transform'])
        .afterClearStyles(['transform'])
        .onFinish(currentStep => {
        // only reset background color if this is the last card-style modal
        if (currentStep !== 1) {
          return;
        }
        presentingEl.style.setProperty('overflow', '');
        const numModals = Array.from(bodyEl.querySelectorAll('ion-modal')).filter(m => m.presentingElement !== undefined).length;
        if (numModals <= 1) {
          bodyEl.style.setProperty('background-color', '');
        }
      });
      const bodyEl = document.body;
      if (isMobile) {
        const transformOffset = (!CSS.supports('width', 'max(0px, 1px)')) ? '30px' : 'max(30px, var(--ion-safe-area-top))';
        const modalTransform = hasCardModal ? '-10px' : transformOffset;
        const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
        const finalTransform = `translateX(${modalTransform}) scale(${toPresentingScale})`;
        presentingAnimation
          .addElement(presentingEl)
          .keyframes([
          { offset: 0, filter: 'contrast(0.85)', transform: finalTransform, borderRadius: '10px 10px 0 0' },
          { offset: 1, filter: 'contrast(1)', transform: 'translateX(0px) scale(1)', borderRadius: '0px' }
        ]);
        baseAnimation.addAnimation(presentingAnimation);
      }
      else {
        baseAnimation.addAnimation(backdropAnimation);
        if (!hasCardModal) {
          wrapperAnimation.fromTo('opacity', '1', '0');
        }
        else {
          const toPresentingScale = (hasCardModal) ? SwipeToCloseDefaults.MIN_PRESENTING_SCALE : 1;
          const finalTransform = `translateX(-10px) scale(${toPresentingScale})`;
          presentingAnimation
            .addElement(presentingEl.querySelector('.modal-wrapper'))
            .afterStyles({
            'transform': 'translate3d(0, 0, 0)'
          })
            .keyframes([
            { offset: 0, filter: 'contrast(0.85)', transform: finalTransform },
            { offset: 1, filter: 'contrast(1)', transform: 'translateX(0) scale(1)' }
          ]);
          const shadowAnimation = new AnimationController().create()
            .addElement(presentingEl.querySelector('.modal-shadow'))
            .afterStyles({
            'transform': 'translateX(0) scale(1)'
          })
            .keyframes([
            { offset: 0, opacity: '0', transform: finalTransform },
            { offset: 1, opacity: '1', transform: 'translateX(0) scale(1)' }
          ]);
          baseAnimation.addAnimation([presentingAnimation, shadowAnimation]);
        }
      }
    }
    else {
      baseAnimation.addAnimation(backdropAnimation);
    }
    return baseAnimation;
  };

1.创建一个新文件名。ts复制并粘贴此文件...然后只将此文件导入到您将创建模态的组件。*import { leaveToRightAnimation,enterFromRightAnimation} from 'filename';不需要将其导入模块 *
1.然后设置模态选项
enterAnimation:从右侧进入动画,离开动画:从左向右动画

相关问题