【问题标题】:Ionic custom modal animation离子自定义模态动画
【发布时间】:2015-10-03 06:30:40
【问题描述】:

离子模态带有slide-in-up的标准动画。能不能把动画改成fade-in

【问题讨论】:

    标签: angularjs animation ionic-framework


    【解决方案1】:

    为了为 Ionic Modal 添加自定义转换,我们将使用 Ionic Modal Options enterAnimationleaveAnimationfrom ModalOptions 接口。对于一个模态有过渡状态:当我们关闭它时,模态的 On Enter 和模态的 On Leave。如果您查看 Ionic Modal 选项界面,您会发现 2 个选项可以为两种状态添加动画。

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

    我们将在模态中使用这些选项来指定我们使用来自ionic-angular 的动画类创建的过渡类。那么让我们来看看我们如何一步一步地创建和自定义动画。

    为进入和离开创建2个转换类:

    on-enter-translate.transition.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);
        }
    }
    

    on-leave-translate.transition.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

    【讨论】:

      【解决方案2】:

      您可以添加自己的动画 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

      【讨论】:

        【解决方案3】:

        no ionic 不提供淡入动画。 但是你可以通过使用animate.css 来做到这一点

        【讨论】:

        • 我认为这对页面元素动画很有好处,但对于从屏幕到屏幕本身的过渡则不适用
        【解决方案4】:

        你可以使用这个开源的准备好的动画:

        Ionic v3 的模态/弹出框过渡类here

        【讨论】:

          【解决方案5】:
           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'; 不需要导入到模块中
          2. 然后设置模态选项enterAnimation: enterFromRightAnimation, leaveAnimation: leaveToRightAnimation

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-04-12
            • 1970-01-01
            • 2013-04-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多