iOS中的转场研究(2)

安全运
• 阅读 4926

自iOS5引入Storyboard之后,iOS开发者在除了原有的Nib开发的基础上又有了新的方式来组织自己的UI和流程。Storyboard相对于传统的Nib,能够更加清晰的体现业务的流程,因此很受开发者欢迎。如今,很多教程都以Storyboard开发方式来讲解。而Storyboard中的Segue则是对转场流程的进一步封装。这个概念在Storyboard中至关重要,也是实现自定义转场的关键角色。

自定义Segue

自定义Segue的方式很简单,只要创建一个UIStoryboardSegue子类,并实现其perform方法即可。一个简单的实现如下:

- (void)perform 
{
    // Modal presentation segue
    UIViewController *fromController = self.sourceViewController;
    UIViewController *toController = self.destinationViewController;

    [fromController presentViewController:toController animated:YES completion:^{
        // Completion code here
    }];
}

或者

- (void)perform 
{
    // Navigation ViewController segue(Push segue, Show segue in iOS8).
    UIViewController *fromController = self.sourceViewController;
    UIViewController *toController = self.destinationViewController;

    [fromController.navigationController pushViewController:toController animated:YES];
}

自定义Unwind Segue

自定义Unwind Segue的方式与上面几乎完全一样,只不过调用的接口由presentViewController:animated:completion:pushViewController:animated:换成dismissViewControllerAnimated:completion:popToViewController:animated:
但是Unwind Segue与普通的Segue有一个很大的不同,就是Unwind Segue的调用通常是由一个Container View Controller完成的。在iOS SDK的UIKit框架中,Navigation View Controller和TabBar View Controller都是常用的Container View Controller。

那么为什么Unwind Segue需要一个Container View Controllerl的支持?

这里就需要提一下Unwind Segue的设计初衷及其工作方式。之所以引入Unwind Segue,是为了应付任意跳转的情况,即从任意一个View Controller转场到特定的View Controller。在Nib的时代,这种工作往往通过delegate来完成。但是有了Unwind Segue以后,我们只要在需要跳转到的这个特定的View Controller类中实现一个签名为- (IBAction)unwindMethod:(UIStoryboardSegue *)segue这样的方法即可(其中unwindMethod可以替换为任何你喜欢的名称,但注意,当存在多个这样的方法时,名称不要相同,以免发生冲突,造成不可预料的后果)。这样,我们就可以在任意的View Controller(除了含有这个方法本身的View Controller)通过连接Segue来实现任意View Controller跳转到当前View Controller。不用再多写一行代码,这些都可以通过Interface Builder搞定,非常方便。

Unwind Segue的工作原理大致如下1

  • 当我们通过UI事件或手动调用performSegueWithIdentifier:sender:方法触发一个Unwind Segue以后,首先UIKit会发送canPerformUnwindSegueAction:fromViewController:withSender:消息到sourceViewController询问是否处理UnwindSegue的action,由于sourceViewController不能处理(Unwind到自身没有意义),会返回NO
  • UIKit然后会寻找sourceViewController的父Controller。如果sourceController是嵌入Navigation View Controller的子Controller,那么父Controller就是其navigationController
  • 之后UIKit会发送viewControllerForUnwindSegueAction:fromViewController:withSender:消息给navigationController,询问能否找到一个负责处理此action的子Controller
  • 在navigationController的默认viewControllerForUnwindSegueAction:fromViewController:withSender:实现中,navigationController会向自己的navigation栈上的所有子Controller发送canPerformUnwindSegueAction:fromViewController:withSender:消息。UIViewController类中,该方法的默认实现会查看unwinde segue action定义是否存在(即上面提到的特定签名的方法是否存在,这个方法的内部实现可以留空),若存在就返回YES。
  • 如果navigationController的viewControllerForUnwindSegueAction:fromViewController:withSender:方法返回nil,则不会触发任何Unwind Segue
  • 如果navgationController找到一个子类可以处理Unwind Segue的action,那么UIKit会发送segueForUnwindingToViewController:fromViewController:identifier:消息给navigationController,此方法将返回一个实际执行定制转场的segue实例
  • 调用sourceViewController上的prepareForSegue:sender:方法
  • 调用由viewControllerForUnwindSegueAction:fromViewController:withSender:方法返回的destinationViewController中的Segue action方法
  • 调用Unwind Segue实例中的perform方法

从上面的我们可以知道,Unwind Segue的正常工作必须要有一个Container View Controller作为所有流程View Controller的父Controller来管理整个流程。在上面的原理说明中,这个父Controller是Navigation View Controller。如果我们要实现一个自己的定义的Container,就必须给自定义的View Controller类实现一些上面提到过的方法:

  • canPerformUnwindSegueAction:fromViewController:withSender:
  • viewControllerForUnwindSegueAction:fromViewController:withSender:
  • segueForUnwindingToViewController:fromViewController:identifier:

关于这些方法的说明和实现方式,我将在下一篇文章中详细讨论。


  1. 参考iOS6 by Tutorial 

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Easter79 Easter79
4年前
storyboard页面切换与传值
一、storyboard页面切换假设viewcontroller1下有一个button1,viewcontroller2下有一个button2,我们要实现storyboard在这两个viewcontroller之间切换。1、Controller1切换Controller2在storyboard界面下,点住button1,右键拖动至cont
Jacquelyn38 Jacquelyn38
4年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
4年前
(转)直接拿来用!最火的iOS开源项目(二)
“每一次的改变总意味着新的开始。”这句话用在iOS上可谓是再合适不过的了。GitHub上的iOS开源项目数不胜数,iOS每一次的改变,总会引发iOS开源项目的演变,从iOS1.x到如今的iOS7,有的项目已经被弃用,即使曾经的它很受开发者喜爱,有的项目则继续发扬光大,新项目更是层出不穷。在本文中,我们将继续为大家介绍20个在GitHub上非常受开发者欢迎
Stella981 Stella981
4年前
PhoneGap设置Icon
参考:http://cordova.apache.org/docs/en/latest/config\_ref/images.html通过config.xml中的<icon标签来设置Icon<iconsrc"res/ios/icon.png"platform"ios"width"57"height"57"densi
Stella981 Stella981
4年前
JS 苹果手机日期显示NaN问题
问题描述newDate("2019122910:30:00")在IOS下显示为NaN原因分析带的日期IOS下存在兼容问题解决方法字符串替换letdateStr"2019122910:30:00";datedateStr.repl
Easter79 Easter79
4年前
Storyboard中的UIScrollView使用自动布局,使其能够滚动
在使用storyboard和xib时,我们经常要用到ScrollView,还有自动布局AutoLayout,但是ScrollView和AutoLayout结合使用,相对来说有点复杂。根据实践,我说一下我的理解,在故事板或xib中,ScrollView是根据其下面的一个View的大小来确定ContentSize的大小。看一下效果!(http://
Wesley13 Wesley13
4年前
初探 Objective
作者:Cyandev,iOS和MacOS开发者,目前就职于字节跳动0x00前言异常处理是许多高级语言都具有的特性,它可以直接中断当前函数并将控制权转交给能够处理异常的函数。不同语言在异常处理的实现上各不相同,本文主要来分析一下ObjectiveC和C这两个语言。为什么要把ObjectiveC和
Easter79 Easter79
4年前
Storyboard全解析
故事版(Storyboard)是一个能够节省你很多设计手机App界面时间的新特性,下面,为了简明的说明Storyboard的效果,我贴上本教程所完成的Storyboard的截图:!Thefullstoryboardwe'llbemakinginthistutorial.(http://static.oschina.net/uploa
Easter79 Easter79
4年前
SwiftUI 跨组件数据传递
作者:Cyandev,iOS和MacOS开发者,目前就职于字节跳动0x00前言众所周知,SwiftUI的开发模式与React、Flutter非常相似,即都是声明式UI,由数据驱动(产生)视图,视图也会与数据自动保持同步,框架层会帮你处理“绑定”的问题。在声明式UI中不存在命令式地让一个视图变成xxx
安全运
安全运
Lv1
于过往岁月里,见过朝阳初升。
文章
4
粉丝
0
获赞
0