iOS中的系统转场

更好的阅读体验,请到个人博客阅读: iOS中的系统转场

请忽略标题,😂,本文记录的是对下图所示的Kind, Presentation, Transition的理解:

iOS系统转场

目录如下:

  1. Size Classes
  2. Kind转场类型

<h1 id="size-classes">Size Classes</h1>

开始之前,先来了解一下Size Classes, 从iOS8.0开始引入了Size Classes的概念来对屏幕进行分类:把各个设备屏幕以及它们的屏幕旋转状态都抽象成屏幕Size的变化,下表是不同尺寸设备屏幕对Size Classes的约定。

Device Portrait Landscape
iPad (all)</br>iPad Mini Vertical size class: Regular</br>Horizontal size class: Regular Vertical size class: Regular</br>Horizontal size class: Regular
iPhone 6 Plus Vertical size class: Regular</br>Horizontal size class: Compact Vertical size class: Compact</br>Horizontal size class: Regular
iPhone 6 Vertical size class: Regular</br>Horizontal size class: Compact Vertical size class: Compact</br>Horizontal size class: Compact
iPhone 5s</br>iPhone 5c</br>iPhone 5 Vertical size class: Regular</br>Horizontal size class: Compact Vertical size class: Compact</br>Horizontal size class: Compact
iPhone 4s Vertical size class: Regular</br>Horizontal size class: Compact Vertical size class: Compact</br>Horizontal size class: Compact

宽(正常,任意, 紧凑),高(正常,任意, 紧凑),3 x 3 共 9 种 Size,每种 Size 都可以设置特定的一套布局,如果不特殊指定,默认是在(宽任意,高任意)模式下设置,且其他 8 种布局继承它。对于Size Classes,可以看看博客: iOS8 Size Classes初探

<h1 id="presentation-kind">Kind-转场类型</h1>

先说明一下两个名词,假如view controller A模态展示了view controller B,则

  1. presenting view controller, 是上述场景中的A view controller, 它会负责展示另外一个view controller
  2. presented view controller, 是上述场景中的B view controller,它是由其它控制器展示出来的view controller

下图是Xcode8.0转场Kind的设置选项,可以看到系统默认的类型有四种,Show, Show Detail, Present Modally, Present As Popover

转场类型

<h2 id="presentation-kind-show">Show</h2>

Presents a view controller in a primary context.

func show(_ vc: UIViewController, sender: Any?)

使用该方法可以将display view controllerpresenting that view controller on screen的过程中解耦,ViewController不需要知道它是嵌入到UINavigationController中或者是UISplitViewController中,都可以调用此方法来展示到屏幕上。UISplitViewControllerUINavigationController重写了该方法,使其能够根据自身设计来处理展现过程。例如,UINavigationController重写了该方法,并使用该方法来push viewcontrollernavigation stack中。

该方法的默认实现会调用targetViewControllerForAction:sender:view controller层级中找到重写该方法的对象,然后调用该对象的此方法,使其能够以适当的方式来展现view controller。 如果targetViewControllerForAction:sender:方法返回nil,此方法会使用windowroot view controller来模态显示vc

你可以在自定义view controller中重写该方法来展示vc,你的实现应该在regularcompact环境中做好适配。

官方文档

<h2 id="presentation-kind-showdetail">Show Detail</h2>

Presents a view controller in a secondary (or detail)�� context.

func showDetailViewController(_ vc: UIViewController, sender: Any?)

该方法特点同Show类似:使用该方法可以将display view controllerpresenting that view controller on screen的过程中解耦,ViewController不需要知道它是嵌入到UINavigationController中或者是UISplitViewController中,都可以调用此方法来展示到屏幕上。在regular环境,UISplitViewController重写了该方法,将vcdetail view controller的方式加载;在compact环境,split view controller的该方法实现是调用show(_:sender:)方法。

show(_:sender:)相同:该方法的默认实现会调用targetViewControllerForAction:sender:view controller层级中找到重写该方法的对象,然后调用该对象的此方法,使其能够以适当的方式来展现view controller。 如果targetViewControllerForAction:sender:方法返回nil,此方法会使用windowroot view controller来模态显示vc

你可以在自定义view controller中重载此方法来展示vc,使用此方法来将vc展现在secondary context中,例如,一个容器view controller可能会使用此方法来替换第二子控制器,你的实现应该为regularcompact环境做好适配.

官方文档

<h2 id="presentation-kind-present-modally">Present Modally</h2>

Presents a view controller modally.

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

horizontally regular的环境,view controller会以modalPresentationStyle属性设定的样式进行展现。在horizontally compact环境,view controller默认会以全屏的方式进行展现。对于viewControllerToPresent关联的presentation controller, 如果你实现了其adaptive delegate方法,则可以动态修改presentation style

调用该方法的对象不一定是处理该presentation的对象。每一个presentation style会有不同的规则来处理其行为。例如,full-screen presentation必须由自身覆盖了整个屏幕的view controller来处理。如果调用该方法的当前view controlelr不能满足该要求,则它会沿着view controller的层级向上传递给最近的父控制器,由其父控制器来负责处理或者继续转发该请求。

在展现view controller之前,该方法会基于presentation style来设置presented view controllerview大小。对于大多数的presentation styles,最终视图会以presented view controllermodalTransitionStyle属性设定的转场样式动画来显示到屏幕上。对于自定义的presentations, 视图会以presented view controllertransitioning delegate中要求的动画来展示。对于current context presentations,视图可能会是以当前view controllertransition style来显示到屏幕上,这种情况稍后会再次提到。

注意: completion闭包是在presented view controllerviewDidAppear:的方法调用完成后才会调用。

官方文档

接下来聊聊present modally类型下的presentation style.

<h3 id="presentation-style">Presentation Styles</h3>

view controllerpresentation style控制其在屏幕上的显示。UIKit定义了多种标准的presentation styles, 每一种都有特定的UI展示和用途。当然,你也可以自定义presentation styles。当设计你的app时,根据当前的使用场景选择最合适的presentaion style, 然后设置presented view controllermodalPresentationStyle属性值为对应的常量值。

modalPresentationStyle:
The presentation style determines how a modally presented view controller is displayed onscreen. In a horizontally compact environment, modal view controllers are always presented full-screen. In a horizontally regular environment, there are several different presentation options. For a list of possible presentation styles, and their compatibility with the available transition styles, see the UIModalPresentationStyle constant descriptions.

UIModalPresentationStyle的枚举值定义如下:

public enum UIModalPresentationStyle : Int {

    
    case fullScreen

    @available(iOS 3.2, *)
    case pageSheet

    @available(iOS 3.2, *)
    case formSheet

    @available(iOS 3.2, *)
    case currentContext

    @available(iOS 7.0, *)
    case custom

    @available(iOS 8.0, *)
    case overFullScreen

    @available(iOS 8.0, *)
    case overCurrentContext

    @available(iOS 8.0, *)
    case popover

    @available(iOS 7.0, *)
    case none
}

由于popover需要进行特殊处理,在Xcode中,Presentation处仅有如下图所示的设置:

Presentation设置值

对以上枚举值进行大体分类: full-screen presentation styles, popover style, current context styles, custom presentation styles。其中:

  • full-screen presentation styles对应枚举值fullScreen, pageSheet, formSheet, overFullScreen;
  • popover style对应枚举值popover;
  • current context styles对应枚举值currentContext, overCurrentContext

先看看full-screen presentation styles

<h4 id="full-screen-presentation">Full-Screen Presentation Styles</h4>

Full screen presentation styles cover the entire screen, preventing interactions with the underlying content. In a horizontally regular environment, only one of the full-screen styles covers the underlying content completely. The rest incorporate dimming views or transparency to allow portions of the underlying view controller to show through. In a horizontally compact environment, full-screen presentations automatically adapt to the UIModalPresentationFullScreen style and cover all of the underlying content.

full screen presentation styles会覆盖设备的整个屏幕,阻止用户与底部内容进行交互。在horizontally regular环境,full screen presentation styles中只有一种类型(UIModalPresentationFullScreen)会完全覆盖住底部的内容,其余的类型会结合透明或者黑色半透明的视图来使底部的部分内容显示出来。在horizontally compact环境,所有的full screen presentation styles会自动适配为UIModalPresentationFullScreen类型并覆盖底部的所有内容。

下图是在horizontally regular环境下fullScreen, pageSheet, formSheet样式下的显示效果。图中,左上角的绿色view controllerpresents右上角的蓝色view controller,对于某些presentation styles, UIKit会在两个view controller之间插入dimming view

The full screen presentation styles
The full screen presentation styles
fullScreen

case fullScreen = 0

A presentation style in which the presented view covers the screen. The views belonging to the presenting view controller are removed after the presentation completes.

此种类型的presentation style presented view会完全覆盖屏幕。且属于presenting view controller的视图会在presentation completes后移除视图层级。

注意:当你使用UIModalPresentationFullScreen样式来presenting a view controller的时候,UIKit会在转场动画完成后移除底部控制器(所覆盖的控制器)的视图,如果你想阻止视图的移除,则可以使用UIModalPresentationOverFullScreen样式来替代。当presented view controller设计有透明区域以显示底层内容时,你可能会用到这种样式。

pageSheet

case pageSheet = 1

In a horizontally regular environment, a presentation style that partially covers the underlying content. The presented view'��s width is set to the width of the screen in a portrait orientation and the the height is set to the height of the screen. Any uncovered areas are dimmed to prevent the user from interacting with them. (In portrait orientations, this option is essentially the same as fullScreen.)

In a horizontally compact environment, this option behaves the same as fullScreen.

horizontally regular环境,此种presentation style会部分遮挡底部的内容。presented view的宽度会被设置成与portrait orientation模式下屏幕的宽度相等,且presented view的高度被设置成与设备当前模式(portrait 或者 landscape)下屏幕的高度相同。任何未覆盖到的区域会加黑色透明视图以阻止用户的交互。在portrait orientations场景,该设置大体上与fullScreen相同(该样式下,statusbar上会覆盖黑色透明视图)。在horizontally compact环境下,该样式与fullScreen样式完全相同。

formSheet

case formSheet = 2

In a horizontally regular environment, a presentation style that displays the content centered in the screen. The width and height of the content area are smaller than the screen size and a dimming view is placed underneath the content. If the device is in a landscape orientation and the keyboard is visible, the position of the view is adjusted upward so that the view remains visible. All uncovered areas are dimmed to prevent the user from interacting with them.

In a horizontally compact environment, this option behaves the same as fullScreen.

horizontally regular环境下,formSheet这种样式会将内容布局在屏幕的中间。显示内容的宽高都会比屏幕尺寸小,并且会在显示内容下插入黑色透明视图(dimming view)。如果设备处于landscape orientation并且弹出了键盘,显示内容会向上移动适配以使显示内容仍然可见。所有未被显示内容覆盖到的区域都会被dimmed以阻止用户与其交互。

horizontally compact环境,该选项的效果与fullScreen的效果完全一致。


When using one of the full-screen presentation styles, the view controller that initiates the presentation must itself cover the entire screen. If the presenting view controller does not cover the screen, UIKit walks up the view controller hierarchy until it finds one that does. If it can’t find an intermediate view controller that fills the screen, UIKit uses the root view controller of the window.

当你使用这些full-screen presentation styles时,启动这次presentationview controller必须其自身是覆盖了整个屏幕。如果presenting view controller没有覆盖整个屏幕,则UIKit会沿着view controller的层级一直寻找直到找到满足该条件的view controller,如果没有找到,UIKit则会使用windowroot view controller

<h4 id="popover">The Popover Style</h4>

内容见Presenting a View Controller in a Popover

<h4 id="current-context">The Current Context Styles</h4>

使用UIModalPresentationCurrentContext样式会使presented view controller覆盖你在UI中指定的view controller。你通过设置view controllerdefinesPresentationContext属性值为YES来使其成为被覆盖的对象。下图演示的是curren context presentation仅仅覆盖了split view controller的一个子控制器。

The current context presentation style
The current context presentation style

注意:使用该样式时,对于未被presented view覆盖的区域,用户仍然可以与UI元素(例如UIButton)进行交互。

A presentation style where the content is displayed over a view controller’s content whose definesPresentationContext property is true. UIKit may walk up the view controller hierarchy to find a view controller that wants to define the presentation context. The views belonging to the presenting view controller are removed after the presentation completes.

When presenting a view controller in a popover, this presentation style is supported only if the transition style is coverVertical. Attempting to use a different transition style triggers an exception. However, you may use other transition styles (except the partial curl transition) if the parent view controller is not in a popover.

该样式会将内容显示在属性值definesPresentationContexttrueview controller之上。UIKit会沿着view controller的层级向上寻找定义了presentation contextview controller。属于presenting view controller的视图会在presentation completes后移除。

当在一个popover中来presenting view controller时,只有当transition stylecoverVertical时才支持此种样式,使用其它类型的transition style会导致crash(经过测试,只有当transition stylespartial curl时才会crash,不过小心为妙)。当parent view controller不在popover中时,你可以使用除partial curl外的其它transition styles

当转场结束时,属于presented view controller的视图会被移除,你可以使用UIModalPresentationOverCurrentContext样式来替代以避免被移除,你可能会在当presented view controller有透明区域使底部内容显示出来时使用此样式。

定义成为presentation contextview controller, 也可以在其内定义presentation时使用的转场动画。通常情况下,UIKit会使用presented view controllermodalTransitionStyle属性定义的动画将presented view controller显示到屏幕上。如果presentation context view controller的属性providesPresentationContextTransitionStyle值为YES,则UIKit会使用该view controllermodalTransitionStyle属性值来执行动画。

当转换到horizontally compact环境时,current context样式会适配为UIModalPresentationFullScreen样式。如果要想改变这种适配行为,可以使用adaptive presentation delegate来指定另一种presentation style或者更换view controller

<h4 id="custom-presentation">Custom Presentation Styles</h4>

UIModalPresentationCustom允许你使用自定义的样式来展示view controller。创建自定义的样式需要你子类化UIPresentationController并且使用其方法来将自定义视图动画显示到屏幕,定义其大小和设置presente view controller的大小。

更多信息参考: Creating Custom Presentations

<h3 id="transiton-style">Transition Styles</h3>

Transition styles determine the type of animations used to display a presented view controller. For the built-in transition styles, you assign one of the standard transition styles to the modalTransitionStyle property of the view controller you want to present. When you present the view controller, UIKit creates the animations that correspond to that style. For example, Figure 8-4 illustrates how the standard slide-up transition (UIModalTransitionStyleCoverVertical) animates the view controller onscreen. View controller B starts offscreen and animates up and over the top of view controller A. When view controller B is dismissed, the animation reverses so that B slides down to reveal A.

transition styles决定了显示presented view controller时所用的动画类型。对于系统内置的transition styles,你可以通过对presented view controllermodalTransitionStyle属性赋值来指定样式。当你显示view controller时,UIKit属性值对应的动画。例如,下图演示了系统UIModalTransitionStyleCoverVertical样式对应的显示动画。view controller B从不可见->往上滑进屏幕->覆盖view controller A。当view controller B退场时,它会向下滑出屏幕以显示view controller A

A transition animation for a view controller
A transition animation for a view controller

You can create custom transitions using an animator object and transitioning delegate. The animator object creates the transition animations for placing the view controller onscreen. The transitioning delegate supplies that animator object to UIKit at the appropriate time. For information about how to implement custom transitions, see Customizing the Transition Animations

目前iOS支持的系统转场类型如下图所示:

iOS默认转场动画类型

经过测试,Partial Curl转场只有在PresentationFull Screen时才会有效,其余presentation styles会导致crash,不知道是我使用的方式不对或者是其它原因,请指教。

<h2 id="presenting-popover">Presenting a View Controller in a Popover</h2>

同上,这种方式也是使用api:

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

来展现视图。与上不同的是,popover的展现方式还需要额外的配置。在设置 model presentation style值为UIModalPresentationPopover之后,配置如下与popover相关的属性值:

  • 设置presented view controllerpreferredContentSize,将视图大小设置为期望的大小;
  • presented view controllerpopoverPresentationController属性中获取关联的UIPopoverPresentationController对象,然后设置该对象的锚点。设置锚点可从如下两种方式中任选一种:
    • 设置barButtonItem属性值为一个bar button item;
    • 设置sourceViewsourceRect属性值为视图中的特定区域;

你可以使用UIPopoverPresentationController对象来修改popover最终绘制出来的效果。popover presentation controller同样也支持使用一个delegate对象来监听presentation过程以做出对应的响应。例如,你可以使用该delegate对象来监听popoverappears, disappears, 或者repositioned on the screen事件,以做出对应的响应。关于该对象的更多信息,请参考: UIPopoverPresentationController Class Reference

UIModalPresentationPopover样式会以浮层的形式显示view controller.Popovers可用来显示一些额外信息,或者,是当前聚焦或者选中对象关联的对象列表。在horizontally regular环境,弹出的浮层只会覆盖屏幕的一部分,如下图所示。在horizontally compact环境,popovers会默认适配为UIModalPresentationOverFullScreen样式。在浮层以外的区域点击则会自动使浮层消失。

The popover presentation style
The popover presentation style

由于popovershorizontally compact环境下会自动适配为full-screen presentations,你需要编辑你的浮层代码以处理这种适配。在full-screen模式下,你需要一种方式来使presented popover消失。你可以添加一个按钮,将popover嵌入到可dismissible的容器视图控制器中,或者是修改该适配行为。

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

推荐阅读更多精彩内容