iOS 实现自定义页面跳转(一)

现在的app很少只有一个页面的,在不同页面间的跳转成为了iOS开发人员需要知道的技术点。UIKit 中已经为我们实现了一些系统自带的页面跳转方法,但是程序员这种充满脑洞的特殊人群怎么能够只满足于那些不fashion的跳转呢?因此本着您可将自己累死也要让用户酷炫(不爽?)的态度,我们还是很有必要去知道如何实现一个自定义的页面跳转的。

一, UINavigationController 和 present view controller

在学习自定义页面跳转之前,我们可以先了解一下UIKit已经为我们实现的页面跳转方法。当然已经清楚的同学可以往下看了。
首先我们需要明白的一点是,UINavigationController其实是一种 Container View Controller

Container view controllers are a way to combine the content from multiple view controllers into a single user interface. Container view controllers are most often used to facilitate navigation and to create new user interface types based on existing content. Examples of container view controllers in UIKit include UINavigationController, UITabBarController, and UISplitViewController, all of which facilitate navigation between different parts of your user interface.

从上面的定义我们可以明白以下三点
一,Container view controller 是用来将多个view controller中的内容结合到同一个用户交互界面的。
二,Container view controller可以很方便的进行页面导航并且基于已有的内容创建新的页面交互类型。
三,UINavigationController, UITabBarController, and UISplitViewController这些在UIKit中的类都属于Container view controller。


接下来让我们看看UINavigationViewController的一般用法

##创建 UINavigationViewController并设置root view controller
UIViewController *vc = [[UIViewController alloc] init];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc]; 
self.window.rootViewController = nav;
##通过push跳转页面
UIViewController *viewController = [[UIViewController alloc] init];
[self.navigationController pushViewController:viewController animated:YES];
##通过pop跳转页面
[self.navigationController popViewControllerAnimated:YES];
UINavigationController

在这里我们大概应该明白,navigation controller通过一个数组来维护加入的view controller,并实现了栈的原理来push和pop已经在数组中的view controller。


以下两个实例方法属于UIViewController,通过以下两个实例方法可以很方便的实现跳转。

- (void)presentViewController:(UIViewController *)viewControllerToPresent 
                     animated:(BOOL)flag 
                   completion:(void (^)(void))completion;
- (void)dismissViewControllerAnimated:(BOOL)flag 
                           completion:(void (^)(void))completion;

二,A Custom Present Transition & A Custom Dismiss Transition

对于一个自定义的跳转来说我们首先要明白跳转都做了些什么?

  • 规范跳转发生所需的时间和跳转时所需的交互方法
  • 提供具体的交互方法对象,也就是实现一个交互方法提供给系统跳转时调用

清楚了以上两点我们就比较好理解以下两个我们需要实现的协议了

UIViewControllerTransitioningDelegate的定义

An object that implements the UIViewControllerTransitioningDelegate protocol vends the objects used to manage a fixed-length or interactive transition between view controllers. When you want to present a view controller using a custom modal presentation type, set its modalPresentationStyle property to UIModalPresentationCustom and assign an object that conforms to this protocol to its transitioningDelegate property. When you present that view controller, UIKit queries your transitioning delegate for the objects to use when animating the view controller into position.

UIViewControllerAnimatedTransitioning的定义

Adopt the UIViewControllerAnimatedTransitioning protocol in objects that implement the animations for a custom view controller transition. The methods in this protocol let you define an animator object, which creates the animations for transitioning a view controller on or off screen in a fixed amount of time. The animations you create using this protocol must not be interactive. To create interactive transitions, you must combine your animator object with another object that controls the timing of your animations.

以上的定义我就不再翻译了,相信通过或者没通过四级考试的你都是可以看懂的。😊

协议与View Controller之间的关系

** 从上面的关系图我们可以明白不同模块之间的关系,首先需要有一个UIViewController类去实现UIViewControllerTransitioningDelegate。UIViewControllerTransitioningDelegate会从Animation Controller获得一个交互对象,Animation Controller通过实现UIViewControllerAnimatedTransitioning协议来提供交互,Transitioning Context对象实现UIViewContextTransitioning协议,通过Transitioning Context我们可以获得有关view controller的上下文信息。**

好了,不写代码讲解的程序员都是耍流氓,让我们开始耍流氓吧!😂

1, 实现一个animator object
#import <Foundation/Foundation.h>
//敲黑板1
@interface BouncePresentAnimationController : NSObject<UIViewControllerAnimatedTransitioning>

@end
#import "BouncePresentAnimationController.h"

@implementation BouncePresentAnimationController
//敲黑板2
-(NSTimeInterval) transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
    return 1.0;
}

//敲黑板3
-(void) animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
    //敲黑板4
    UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    CGRect finalFrame = [transitionContext finalFrameForViewController:toViewController];
    
    //敲黑板5
    UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    
    //敲黑板6
    UIView *containerView = [transitionContext containerView];
    CGRect screenBounds = [[UIScreen mainScreen] bounds];
    toViewController.view.frame = CGRectOffset(finalFrame, 0, screenBounds.size.height);
    [containerView addSubview:toViewController.view];
    
    NSTimeInterval duration = [self transitionDuration:transitionContext];
    
    //敲黑板7
    [UIView animateWithDuration:duration delay:0.0 usingSpringWithDamping:0.6 initialSpringVelocity:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
        fromViewController.view.alpha = 0.5;
        toViewController.view.frame = finalFrame;
    } completion:^(BOOL finished){
     fromViewController.view.alpha = 1.0;
     [transitionContext completeTransition:YES];
        }
    ];
}

@end

1, 创建一个实现动画的类继承自NSObject并且实现UIViewControllerAnimatedTransitioning协议。
2,实现transitionDuration方法,这个方法UIKit会自动调用这个方法来获得跳转动画所需的时间。我们在后面将显式调用这个方法。
3, 实现animateTransition方法,UIKit会掉用这个方法,这个方法将告诉动画对象如何实现我们所需的动画效果。
4, 通过transitionContext获得toViewController,toViewController是我们将要显示的视图控制器。
5,通过transitionContext获得fromViewController,fromViewController是我们在进行跳转前正在显示的视图控制器。
6,通过transitionContext获得containerView,containerView是进行动画跳转的容器。我们需要将toViewController.view加入这个containerView,这样toViewController.view将被加入视图结构中。我们才能在跳转之后显示这个view。
7,UIView的动画方法来实现跳转动画。

toView&fromView

上面这幅图描述了在presentation和dismissal这两个跳转过程中页面对应的关系。有兴趣的同学可以查看

2,实现UIViewControllerTransitioningDelegate

接下来我们需要在进行页面跳转的view controller中实现UIViewControllerTransitionsingDelegate协议,并且将要跳转显示的toViewController.transitioningDelegate = self.
在这里我们需要实现一个UIViewControllerTransitioningDelegate方法。

-(id<UIViewControllerAnimatedTransitioning>) animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
    return _bouncePresentAnimationController;
}

在这里,UIKit在页面跳转的时候掉用以上的方法,我们在这里返回一个我们已经实现并且创建的动画对象,UIKit通过这个已经实现的动画对象完成页面跳转过程中的动画效果。

3,如何实现页面dismissal

其实页面的消失也是一样的道理,通过实现以上所提到的两个协议我们就可以实现相关的动画效果了。有兴趣的同学可以看Demo

三,参考内容

1,《iOS 7 By Tutorials》
2, UIViewControllerTransitioningDelegate
3, UIViewControllerAnimatedTransitioning
4, View Controller Programming Guide for iOS

这篇文章主要是对于自定义页面跳转的基本概念介绍和基本使用方法,下一片文章将讲解如何实现可进行用户界面互动的自定义页面跳转并且实现一个UIPresentationController子类来实现页面跳转的封装。

欢迎大家阅读指正,如果喜欢请不吝点赞!😊

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容