iOS-总结Demo--Push、Pop 、Present、Dissmiss动画

iOS-总结Demo--Push、Pop 、Present、Dissmiss动画_第1张图片
梧桐更兼细雨,到黄昏、点点滴滴。这次第,怎一个、愁字了得!<爱心鱼>

小结一下跳转页面的动画效果实现思路!
代码移步GitHub

总结的转场动画是下面几个情况:

  • 导航控制器的 Push 动画和 Pop 动画
  • 普通控制器的 Present 动画和 Dismiss动画,

思路简析:

  • 跳转的控制器遵守 UINavigationControllerDelegate 协议,从而实现 Pop 和 Push 的跳转动画。

通过 operation == UINavigationControllerOperationPush 或者 UINavigationControllerOperationPop 区分是 Push 还是 Pop

  • (nullable id )navigationController:(UINavigationController *)navigationController
    animationControllerForOperation:(UINavigationControllerOperation)operation
    fromViewController:(UIViewController *)fromVC
    toViewController:(UIViewController *)toVC```
  • 跳转的控制器遵守UIViewControllerTransitioningDelegate协议, 从而实现 Present 和 Dissmiss跳转动画

Present:

  • (nullable id )animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source;

Dissmiss:

  • (nullable id )animationControllerForDismissedController:(UIViewController *)dismissed;```
  • 上述的几个方法都是 返回一个遵守UIViewControllerAnimatedTransitioning协议的对象,而主要的动画实现就是写在这个对象当中!我们只要封装好这个类型的对象,在上述方法中返回对应实例对象就能实现动画效果!

UIViewControllerAnimatedTransitioning协议 主要实现两个方法

-(NSTimeInterval)transitionDuration: transitionContext: 跳转的时间
-(void)animateTransition: transitionContext 所要执行的动画在这里实现 ```

其中第二个方法传入的参数是泛型的UIViewControllerContextTransitioning对象
可以通过下面它的的实例方法获取我们需要展示动画的相关属性

#  这个方法获得的是 控制整个跳转的页面 (API 描述:这个视图是动画发生的地方(画布))(将要跳转到的控制器的view添加到画布上执行动画)
- (nullable UIView *)containerView
#  Key 取值 UITransitionContextFromViewControllerKey  (源控制器)UITransitionContextToViewControllerKey(目标控制器)
- (nullable __kindof UIViewController *)viewControllerForKey:(NSString *)key
#  Key 取值  UITransitionContextFromViewKey(源视图)  UITransitionContextToViewKey(目标视图)
- (nullable __kindof UIView *)viewForKey:(NSString *)key

简单效果展示:

iOS-总结Demo--Push、Pop 、Present、Dissmiss动画_第2张图片
演示——跳转.gif

上代码:

第一步: 是封装一个实现动画的类(PP_Transition),遵循UIViewControllerAnimatedTransitioning协议

PP_Transition.h中

  • 导入 UIKit 框架

import ```

  • 定义一个枚举类型,方便我们区分场景

枚举判断使用场景

typedef NS_OPTIONS(NSUInteger, AnimatedScene)
{
AnimatedScenePush = 0, // 值为 0
AnimatedScenePop = 1 << 0, // 值为 2 的 0次
AnimatedScenePresent = 1 << 1, // 值为 2 的 1次
AnimatedSceneDissmiss = 1 << 2 // 值为 2 的 2次
};

- 声明一个自定义初始化方法

>```code
- (instancetype)initWithStytle:(AnimatedScene)scene;```

-------
####PP_Transition.m中
>- 延展一个属性 用来记录初始化的类型

>```code
{
    AnimatedScene _scenceStyle;
}```
- 实现自定义初始化方法

>```code
- (instancetype)initWithStytle:(AnimatedScene)scene
{
    if (self = [super init])
    {
        _scenceStyle = scene;
    }
    return self;
}
  • 实现协议方法1: 转场动画持续时间
  • (NSTimeInterval)transitionDuration:(id)transitionContext{
    return 1.0;
    }```
  • 实现协议方法2: 具体去实现转场的动画 (这里我就是简单的实现几个动画, 我们可以根据具体的情况加以实现)
  • 如果我们想加一些更好的效果,可以尝试在画布(containerView) View 上加上一些自定义的View 用来遮挡或者当做背景(比如 Pop回来时候目标View变大时候加一个背景),记住最后移除掉就行!这是一种思路!
- (void)animateTransition:(id)transitionContext
{
   // 获取到 containerView视图 (我们动画发生的载体)
   UIView *containerView = [transitionContext containerView];
   // 我们要去的 View
   UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey];
   // 从哪个 View 去的
   UIView *fromView = [transitionContext viewForKey:UITransitionContextFromViewKey];
    switch (_scenceStyle)
   {
       case AnimatedScenePush:
       {// Push 动画 这里只是举个例子  动画效果可以自己去使用
           // 注意点: 一定要把目的视图(要去的 View) 添加到容器(containerView)上.
           [UIView animateWithDuration:1.0 animations:^{
               fromView.transform = CGAffineTransformMakeScale(0.5, 0.5);
           } completion:^(BOOL finished) {
               [containerView addSubview:toView];
               // 这个方法大概就是完成过渡动画,更新内部视图,控制器状态的转变!
               [transitionContext completeTransition:YES];
           }];
           
           NSLog(@"Push 动画效果");
       }
          break;
       case AnimatedScenePop:
       {
           // Pop 动画
           [UIView animateWithDuration:1.0 animations:^{
               // 让当前的二级页面  从下方消失
               fromView.frame = CGRectMake(0, kScreenH, kScreenW, kScreenH);
               
           } completion:^(BOOL finished) {
               
               [containerView addSubview:toView];
               
               [UIView animateWithDuration:1.0 animations:^{
                   // 让首级页面  由小变大
                   toView.transform = CGAffineTransformMakeScale(1, 1);
                   
               } completion:^(BOOL finished) {
                   
                   // 完成过度动画
                   [transitionContext completeTransition:YES];
               }];
           }];
           NSLog(@"Pop 动画效果");

       }
           
           break;
       case AnimatedScenePresent:
       {
           
           toView.frame = CGRectMake(kScreenW / 2.0 , kScreenH / 2.0, 0, 0);
           
           [containerView addSubview:toView];
           
           [UIView animateWithDuration:1.0 animations:^{
             
              toView.frame = CGRectMake(0 , 0, kScreenW, kScreenH);
           
           } completion:^(BOOL finished) {
               
               [transitionContext completeTransition:YES];
           }];
           
           NSLog(@"Present 动画效果");
           

       }
           break;
       case AnimatedSceneDissmiss:
       {
         
           [UIView animateWithDuration:1.0 animations:^{
           // 让当前的二级页面  从上方消失
               fromView.frame = CGRectMake(0, -kScreenH, kScreenW, kScreenH);
               
           } completion:^(BOOL finished) {
               
               [containerView addSubview:toView];
           // 完成过度动画
               [transitionContext completeTransition:YES];
            
           }];
           NSLog(@"Dissmiss 动画效果");

       }
           break;
           
       default:
           break;
   }

}

在跳转的控制器中:

  • 首先遵守代理
  • 设置代理
     // 设置 导航控制器代理完成 push 和 pop
    self.navigationController.delegate = self;
     // 设置 模态转场过渡代理
    目的控制器Vc.transitioningDelegate = self;
    目的控制器Vc.modalPresentationStyle = UIModalPresentationCustom;```

>- 代理方法实现

```code
// 导航控制器的跳转动画代理方法  在这里完成 Push 和 Pop 动画
- (id)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
{
    return operation == UINavigationControllerOperationPush ? [[PP_Transition alloc] initWithStytle:(AnimatedScenePush)] : [[PP_Transition alloc] initWithStytle:(AnimatedScenePop)];
}

// 完成转场 Present 动画代理
- (id)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
{
    NSLog(@"----------->Present 一级视图控制器中");
    return [[PP_Transition alloc] initWithStytle:(AnimatedScenePresent)];
}
// 转场 Dissmiss 动画 代理
- (id)animationControllerForDismissedController:(UIViewController *)dismissed
{
    NSLog(@"----------->Dissmiss 一级视图控制器中");
    return [[PP_Transition alloc] initWithStytle:(AnimatedSceneDissmiss)];
}

最后说一句:

我开始写的类名不太好, 弄了一半想改的话可以这样!

.h选中要改的类名 ---> 菜单栏选中 Edit ---> Refactor ---> Rename

iOS-总结Demo--Push、Pop 、Present、Dissmiss动画_第3张图片
改过之后,之前用到这个类名的地方全部都换过来了.png

你可能感兴趣的:(iOS-总结Demo--Push、Pop 、Present、Dissmiss动画)