0%

天天品尝 iOS7 甜点 Day10:Custom UIViewController Transitions

自定义视图控制器转场

参考

  • GitHub 源码:shinobicontrols/iOS7-day-by-day
  • 天天品尝 iOS7 甜点 :: Day 10 :: Custom UIViewController Transitions

转场效果

默认的 UINavigationController 转场 push/pop 是这样的:

现在我们要实现自定义实现视图控制器转场效果:

视图层次结构

视图层次结构很简单:一个 UINavigationController 作为窗口的根视图控制器、而首页是 UINavigationController 的根视图控制器、首页可以 push 到第二页:

要想实现自定义视图控制器转场效果,需要实现 UINavigationControllerDelegate 协议。

UINavigationController 实例对象中声明某个类(HQLNavControllerDelegate)实现了 UINavigationControllerDelegate 协议:

#import "HQLNavigationController.h"
#import "HQLNavControllerDelegate.h"

@interface HQLNavigationController () {
    id<UINavigationControllerDelegate> _navDelegate;
}

@end

@implementation HQLNavigationController

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        _navDelegate = [HQLNavControllerDelegate new];
        self.delegate = _navDelegate;
    }
    return self;
}

上面代码中把实现转场效果的协议方法封装成了一个类 HQLNavControllerDelegate

// ****************************************************
//  HQLNavControllerDelegate.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface HQLNavControllerDelegate : NSObject <UINavigationControllerDelegate>

@end


// ****************************************************
//  HQLNavControllerDelegate.m
#import "HQLNavControllerDelegate.h"
#import "HQLFadeTransition.h"

@implementation HQLNavControllerDelegate

- (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                            animationControllerForOperation:(UINavigationControllerOperation)operation
                                                         fromViewController:(UIViewController *)fromVC
                                                           toViewController:(UIViewController *)toVC{
    return [HQLFadeTransition new];
}

@end

而在 HQLNavControllerDelegate 类中又把实现自定义转场效果的转场动画封装成了一个类 HQLFadeTransition

// ****************************************************
//  HQLFadeTransition.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface HQLFadeTransition : NSObject <UIViewControllerAnimatedTransitioning>

@end


// ****************************************************
//  HQLFadeTransition.m
#import "HQLFadeTransition.h"

@implementation HQLFadeTransition

// @required 方法:返回动画的时长
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
    return 2.0;
}

// @required 方法:实现视图控制器之间的转场效果
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {

    // 1️⃣ viewControllerForKey:获取与转场相关的两个视图控制器
    // UITransitionContextFromViewControllerKey
    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    // UITransitionContextToViewControllerKey
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

    // 2️⃣ containerView - 动画发生的容器视图
    UIView *containerView = [transitionContext containerView];

    // 3️⃣ 将两个视图控制器的子视图添加到容器视图
    [containerView addSubview:fromVC.view];
    [containerView addSubview:toVC.view];
    // 4️⃣ 将要转换到的那个视图设置为透明
    toVC.view.alpha = 0.0;

    // 5️⃣ 执行动画
    [UIView animateWithDuration:[self transitionDuration:transitionContext]
                          delay:0
                        options:0
                     animations:^{
                         // 动画效果
                         toVC.view.alpha = 1.f;
                     }
                     completion:^(BOOL finished) {
                         // 移除旧视图控制器视图
                         [fromVC.view removeFromSuperview];
                         // 告诉 transitionContext 上下文,动画完成啦!
                         [transitionContext completeTransition:YES];
                     }];

}

// 转换完成后调用
- (void)animationEnded:(BOOL) transitionCompleted {
    NSLog(@"Transition Completed!");
}

@end

The end.

欢迎关注我的其它发布渠道