自定转换场地动漫 Swift3.0版本号

摘要: 转换场地动漫这件事情,说简易也简易,pletion:这一组涵数以多形式主视图的方法呈现、掩藏主视图。假如采用了navigationController,还能够启用pushViewController:animated:和popViewController这一组...

转换场地动漫这件事情,说简易也简易,pletion:这一组涵数以多形式主视图的方法呈现、掩藏主视图。假如采用了navigationController,还能够启用pushViewController:animated:和popViewController这一组涵数将新的主视图操纵器压栈、弹栈。

下面的图中常有转换场地动漫全是自定的动漫,这种实际效果假如无需自定动漫则难以乃至没法完成:


demo演试

因为录屏的缘故,一些实际效果没法彻底呈现,例如它实际上还适用全屏。

自定转换场地动漫的实际效果完成起來较为繁杂,假如只是是复制一份可以运作的编码却不明白在其中基本原理,就会有将会产生各种各样掩藏的bug。文中循序渐进详细介绍下边好多个专业知识:

传统式的根据闭包的完成方法以及缺陷自定present转换场地动漫互动式(Interactive)转换场地动漫转换场地融洽器与UIModalPresentationCustomUINavigationController转换场地动漫

我来这篇实例教程制作了一个demo,您能够去在我的github上clone出来:CustomTransition,假如感觉有协助还望给个star以示适用。文中以Swift+纯编码完成,相匹配的OC+Storyboard版本号在demo中还可以寻找,那就是iPhone的官方网示范性编码,恰当性更有确保。demo选用来到CocoaPods,您或许必须实行pod install指令并开启.xcworkspace文档。

在刚开始宣布的实例教程前,您最先必须免费下载demo,在编码眼前文本是惨白的,demo中包括的注解得以表述文中全部的专业知识点。次之,您还得掌握这好多个情况专业知识。

From和To

在编码和文本中,常常会出現fromView和toView。假如不正确的了解他们的含意会造成动漫逻辑性彻底不正确。fromView表明当今主视图,toView表明要自动跳转到的主视图。假如是以A主视图操纵器present到B,则A是from,B是to。从B主视图操纵器dismiss到A时,B变为了from,A是to。用一幅图表明:


from和to Presented和Presenting

这也是一组相对性的定义,它非常容易与fromView和toView搞混。简易来讲,它不会受到present或dismiss的危害,假如是以A主视图操纵器present到B,那麼A一直B的presentingViewController,B一直A的presentedViewController。

modalPresentationStyle 根据block的动漫

非常简单的转换场地动漫是应用transitionFromViewController方式:


传统式的转换场地动漫完成

这一方式尽管早已落伍,可是对它的剖析有利于于后边专业知识的了解。它一现有6个主要参数,前2个表明从哪一个VC刚开始,自动跳转到哪一个VC,正中间2个主要参数表明动漫的時间和选择项。最终2个主要参数表明动漫的实际完成关键点和回调函数闭包。

这六个主要参数实际上便是一次转换场地动漫所必需的六个原素。他们能够分成2组,前2个主要参数为一组,表明网页页面的自动跳转关联,后边四个为一组,表明动漫的实行逻辑性。

这一方式的缺陷之一是可自定水平不太高(在后边您会发觉能自定的不但仅是动漫方法),另外一个缺陷则是器重性不太好,还可以说成藕合度较为大。

在最终2个闭包主要参数中,能够预料的是fromViewController和toViewController主要参数都是被采用,并且她们是动漫的重要。假定主视图操纵器A能够自动跳转到B、C、D、E、F,并且自动跳转动漫基真相似,您会发觉transitionFromViewController方式要被拷贝数次,每一次总是改动小量內容。

自定present转换场地动漫

出自于解耦和提升可自定水平的考虑到,大家来学习培训转换场地动漫的恰当应用姿态。

最先要掌握一个重要定义:转换场地动漫代理商,它是一个完成了UIViewControllerTransitioningDelegate协议书的目标。大家必须自身完成这一目标,它的功效是为UIKit出示下列好多个目标中的一个或好几个:

Animator:

它是完成了UIViewControllerAnimatedTransitioning协议书的目标,用以操纵动漫的不断時间和动漫展现逻辑性,代理商能够为present和dismiss全过程各自出示Animator,还可以出示同一个Animator。

互动式Animator:和Animator相近,但是它是互动式的,后边会出现详尽详细介绍

Presentation操纵器:

它能够对present全过程更为完全的自定,例如改动被展现主视图的尺寸,增加自定主视图等,后边会出现详尽详细介绍。


转换场地动漫代理商

在这里一小标题中,大家最先详细介绍非常简单的Animator。回望一下转换场地动漫必需的6个原素,他们被分成2组,相互中间沒有关系。Animator的功效等同于于第二组的四个原素,换句话说针对同一个Animator,能够可用于A自动跳转B,还可以可用于A自动跳转C。它表明一种通用性的网页页面自动跳转时的动漫逻辑性,不会受到仅限于实际的主视图操纵器。

假如您了解了这一段话,全部自定的转换场地动漫逻辑性就很清晰了,以主视图操纵器A自动跳转到B为例子:

建立动漫代理商,在事儿较为简易时,pletion:并把主要参数animated设定为true系统软件会寻找代理商中出示的Animator,由Animator承担动漫逻辑性

用品体的事例表述便是:

// 这一类非常于A
class CrossDissolveFirstViewController: UIViewController, UIViewControllerTransitioningDelegate {
 // 这一目标非常于B
 crossDissolveSecondViewController.transitioningDelegate = self 
 // 点一下按键开启的涵数
 func animationButtonDidClicked() {
 self.presentViewController(crossDissolveSecondViewController, 
 animated: true, completion: nil)
 // 下边这2个涵数界定在UIViewControllerTransitioningDelegate协议书中
 // 用以为present和dismiss出示animator
 func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) UIViewControllerAnimatedTransitioning? {
// 还可以应用CrossDissolveAnimator,动漫实际效果都有不一样
// return CrossDissolveAnimator()
 return HalfWaySpringAnimator()
 func animationControllerForDismissedController(dismissed: UIViewController) UIViewControllerAnimatedTransitioning? {
 return CrossDissolveAnimator()
}

动漫的重要取决于animator怎样完成,它完成了UIViewControllerAnimatedTransitioning协议书,最少必须完成2个方式,我提议您细心阅读文章animateTransition方式中的注解,它是全部动漫逻辑性的关键:

class HalfWaySpringAnimator: NSObject, UIViewControllerAnimatedTransitioning {
 /// 设定动漫的不断時间
 func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) NSTimeInterval {
 return 2
 /// 设定动漫的开展方法,附带详尽注解,demo中别的地区的这一方式已不表述
 func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
 let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)
 let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)
 let containerView = transitionContext.containerView()
 // 必须关心一下from/to和presented/presenting的关联
 // For a Presentation:
 // fromView = The presenting view.
 // toView = The presented view.
 // For a Dismissal:
 // fromView = The presented view.
 // toView = The presenting view.
 var fromView = fromViewController?.view
 var toView = toViewController?.view
 // iOS8引进了viewForKey方式,尽量应用这一方式而并不是立即浏览controller的view特性
 // 例如在form sheet款式中,大家为presentedViewController的view加上黑影或别的decoration,animator会对全部decoration view
 // 加上动漫实际效果,而这时presentedViewController的view仅仅decoration view的一身高主视图
 if transitionContext.respondsToSelector(Selector( viewForKey: )) {
 fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)
 toView = transitionContext.viewForKey(UITransitionContextToViewKey)
 // 大家让toview的origin.y在显示屏的一半处,那样它从显示屏的正中间部位弹起而并不是从显示屏底端弹起,弹起全过程中慢慢变成不全透明
 toView?.frame = CGRectMake(fromView!.frame.origin.x, fromView!.frame.maxY / 2, fromView!.frame.width, fromView!.frame.height)
 toView?.alpha = 0.0
 // 在present和,dismiss时,务必将toview加上到主视图层级中
 containerView?.addSubview(toView!)
 let transitionDuration = self.transitionDuration(transitionContext)
 // 应用spring动漫,pleteTransition方式
 UIView.animateWithDuration(transitionDuration, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0, options: .CurveLinear, animations: { () Void in
 toView!.alpha = 1.0 // 慢慢变成不全透明
 toView?.frame = transitionContext.finalFrameForViewController(toViewController!) // 移动到特定部位
 }) { (finished: Bool) Void in
 let wasCancelled = transitionContext.transitionWasCancelled()
 pleteTransition(!wasCancelled)
}

animateTransition方式的关键则是以转换场地动漫左右文获得必需的信息内容以进行动漫。左右文是一个完成了UIViewControllerContextTransitioning的目标,它的功效取决于为animateTransition方式出示必需的信息内容。您不可该缓存文件一切有关动漫的信息内容,只是应当一直从转换场地动漫左右原文中获得(例如fromView和toView),那样能够确保一直获得到全新的、恰当的信息内容。


转换场地动漫左右文

获得到充足信息内容后,大家启用UIView.animateWithDuration方式把动漫交到Core Animation解决。pleteTransition方式。

这节的专业知识在Demo的Cross Dissolve文档夹中有详尽的编码。在其中有2个animator文档,这表明大家能够为present和dismiss出示同一个animator,或是各自出示各有相匹配的animator。假如二者动漫实际效果相近,您能够同用同一个animator,唯一的差别取决于:

present时,要把toView添加到container的主视图等级。dismiss时,要把fromView从container的主视图等级中清除。

假如您被前边这一一大段编码和专业知识弄晕了,或是临时用不上这种实际的专业知识,您最少必须记牢自定动漫的基本概念和步骤:

设定即将自动跳转到的主视图操纵器(presentedViewController)的transitioningDelegate当做代理商的目标能够是源主视图操纵器(presentingViewController),还可以是自身建立的目标,它必须为转换场地动漫出示一个animator目标。animator目标的animateTransition是全部动漫的关键逻辑性。 互动式(Interactive)转换场地动漫

不久大家说到,设定了toViewController的transitioningDelegate特性而且present时,UIKit会从代理商处获得animator,实际上这儿也有一个关键点:UIKit还会继续启用代理商的interactionControllerForPresentation:方式来获得互动式操纵器,假如获得了nil则实行非互动式动漫,这就返回了上一节的內容。

假如获得来到并不是nil的目标,那麼UIKit不容易启用animator的animateTransition方式,只是启用互动式操纵器(还还记得前边详细介绍动漫代理商的提示图么,互动式动漫操纵器和animator是平级关联)的startInteractiveTransition:方式。

用下边这一段编码简易表明一下全部步骤(删掉了一部分关键点和注解,请不必为此为恰当参照),详细的编码请参照demo中的Interactivity文档夹:

// 这一非常于fromViewController
class InteractivityFirstViewController: UIViewController {
 // 这一非常于toViewController
 lazy var interactivitySecondViewController: InteractivitySecondViewController = InteractivitySecondViewController()
 // 界定了一个InteractivityTransitionDelegate类做为代理商
 lazy var customTransitionDelegate: InteractivityTransitionDelegate = InteractivityTransitionDelegate()
 override func viewDidLoad() {
 super.viewDidLoad()
 setupView() // 关键是一些UI控制的合理布局,能够忽视实际上现关键点
 /// 设定动漫代理商,这一代理商较为繁杂,因此大家在建了一个代理商目标而并不是让self做为代理商
 interactivitySecondViewController.transitioningDelegate = customTransitionDelegate
 // 开启手式时,也会启用animationButtonDidClicked方式
 func interactiveTransitionRecognizerAction(sender: UIScreenEdgePanGestureRecognizer) {
 if sender.state == .Began {
 self.animationButtonDidClicked(sender)
 func animationButtonDidClicked(sender: AnyObject) {
 self.presentViewController(interactivitySecondViewController, animated: true, completion: nil)
}

非互动式的动漫代理商只必须为present和dismiss出示animator就可以,可是在互动式的动漫代理商中,还必须为present和dismiss出示互动式动漫操纵器:

class InteractivityTransitionDelegate: NSObject, UIViewControllerTransitioningDelegate {
 func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) UIViewControllerAnimatedTransitioning? {
 return InteractivityTransitionAnimator(targetEdge: targetEdge)
 func animationControllerForDismissedController(dismissed: UIViewController) UIViewControllerAnimatedTransitioning? {
 return InteractivityTransitionAnimator(targetEdge: targetEdge)
 /// 前2个涵数和淡入渐隐demo中的完成一致
 /// 后2个涵数用以完成互动式动漫
 func interactionControllerForPresentation(animator: UIViewControllerAnimatedTransitioning) UIViewControllerInteractiveTransitioning? {
 return TransitionInteractionController(gestureRecognizer: gestureRecognizer, edgeForDragging: targetEdge)
 func interactionControllerForDismissal(animator: UIViewControllerAnimatedTransitioning) UIViewControllerInteractiveTransitioning? {
 return TransitionInteractionController(gestureRecognizer: gestureRecognizer, edgeForDragging: targetEdge)
}

animator中的编码略去,它和非互动式动漫中的animator相近。由于互动式的动漫仅仅一种画龙点睛,它务必适用非互动式的动漫,例如这一事例中,点一下按键仍然考虑的是是非非互动式的动漫,仅仅手式拖动才会开启互动式动漫。

class TransitionInteractionController: UIPercentDrivenInteractiveTransition {
 /// 当手式有拖动时开启这一涵数
 func gestureRecognizeDidUpdate(gestureRecognizer: UIScreenEdgePanGestureRecognizer) {
 switch gestureRecognizer.state {
 case .Began: break
 case .Changed: self.updateInteractiveTransition(self.percentForGesture(gestureRecognizer)) //手式拖动,升级百分数
 case .Ended: // 拖动完毕,分辨是不是超出一半,假如是则进行剩余的动漫,不然撤销动漫
 if self.percentForGesture(gestureRecognizer) = 0.5 {
 self.finishInteractiveTransition()
 else {
 self.cancelInteractiveTransition()
 default: self.cancelInteractiveTransition()
 private func percentForGesture(gesture: UIScreenEdgePanGestureRecognizer) CGFloat {
 let percent = 依据gesture测算得到
 return percent
}

互动式动漫是在非互动式动漫的基本上完成的,大家必须建立一个承继自UIPercentDrivenInteractiveTransition种类的子类,而且在动漫代理商中回到这一种类的案例目标。

在这里个种类中,监视手式(或是免费下载进展这些)的時间转变,随后启用percentForGesture方式升级动漫进展就可以。

转换场地融洽器与UIModalPresentationCustom
转换场地动漫融洽器

要想进行gif中第三个案子的实际效果,大家还必须应用UIModalPresentationStyle.Custom来替代.FullScreen。由于后面一种会清除fromViewController,这显而易见不符合合要求。

当present的方法为.Custom时,大家还能够应用UIPresentationController更为完全的操纵转换场地动漫的实际效果。一个 presentation controller具有下列好多个作用:

设定presentedViewController的主视图尺寸加上自定主视图来更改presentedView的外型为一切自定的主视图出示转换场地动漫实际效果依据size class开展自适应网站

您能够觉得,. FullScreen及其别的present设计风格全是swift为大家完成出示好的,他们是.Custom的例外。而.Custom容许大家更为随意的界定转换场地动漫实际效果。

UIPresentationController出示了四个涵数而定义present和dismiss动漫刚开始前后左右的实际操作:

presentationTransitionWillBegin: present即将实行时presentationTransitionDidEnd:present实行完毕后dismissalTransitionWillBegin:dismiss即将实行时dismissalTransitionDidEnd:dismiss实行完毕后

下边的编码扼要叙述了gif中第三个动漫实际效果的完成基本原理,您能够在demo的Custom Presentation文档夹下查询进行编码:

// 这一非常于fromViewController
class CustomPresentationFirstViewController: UIViewController {
 // 这一非常于toViewController
 lazy var customPresentationSecondViewController: CustomPresentationSecondViewController = CustomPresentationSecondViewController()
 // 建立PresentationController
 lazy var customPresentationController: CustomPresentationController = CustomPresentationController(presentedViewController: self.customPresentationSecondViewController, presentingViewController: self)
 override func viewDidLoad() {
 super.viewDidLoad()
 setupView() // 关键是一些UI控制的合理布局,能够忽视实际上现关键点
 // 设定转换场地动漫代理商
 customPresentationSecondViewController.transitioningDelegate = customPresentationController
 override func didReceiveMemoryWarning() {
 super.didReceiveMemoryWarning()
 // Dispose of any resources that can be recreated.
 func animationButtonDidClicked() {
 self.presentViewController(customPresentationSecondViewController, animated: true, completion: nil)
}

关键取决于怎样完成CustomPresentationController这一类:

class CustomPresentationController: UIPresentationController, UIViewControllerTransitioningDelegate {
 var presentationWrappingView: UIView? // 这一主视图封裝了原主视图,加上了黑影和圆弧实际效果
 var dimmingView: UIView? = nil // alpha为0.5的灰黑色蒙版
 // 告知UIKit为哪一个主视图加上动漫实际效果
 override func presentedView() UIView? {
 return self.presentationWrappingView
// 四个方式自定转换场地动漫产生前后左右的实际操作
extension CustomPresentationController {
 override func presentationTransitionWillBegin() {
 // 设定presentationWrappingView和dimmingView的UI实际效果
 let transitionCoordinator = self.presentingViewController.transitionCoordinator()
 self.dimmingView?.alpha = 0
 // 根据转换场地融洽器实行同歩的动漫实际效果
 transitionCoordinator?.animateAlongsideTransition({ (context: UIViewControllerTransitionCoordinatorContext) Void in
 self.dimmingView?.alpha = 0.5
 }, completion: nil)
 /// present完毕时,把dimmingView和wrappingView都清除,这种临时性主视图用不上了
 override pleted: Bool) {
 if !completed {
 self.presentationWrappingView = nil
 self.dimmingView = nil
 /// dismiss刚开始时,让dimmingView彻底全透明,这一动漫和animator中的动漫同时产生
 override func dismissalTransitionWillBegin() {
 let transitionCoordinator = self.presentingViewController.transitionCoordinator()
 transitionCoordinator?.animateAlongsideTransition({ (context: UIViewControllerTransitionCoordinatorContext) Void in
 self.dimmingView?.alpha = 0
 }, completion: nil)
 /// dismiss完毕时,把dimmingView和wrappingView都清除,这种临时性主视图用不上了
 override pleted: Bool) {
 if completed {
 self.presentationWrappingView = nil
 self.dimmingView = nil
extension CustomPresentationController {
}

除此之外,这一类也要解决子主视图合理布局有关的逻辑性。它做为动漫代理商,还必须为动漫出示animator目标,详尽编码请在demo的Custom Presentation文档夹下阅读文章。

UINavigationController转换场地动漫

到现阶段才行,全部转换场地动漫全是可用于present和dismiss的,实际上UINavigationController还可以自定转换场地动漫。二者是平行面关联,许多都可以以对比回来:

class FromViewController: UIViewController, UINavigationControllerDelegate {
 let toViewController: ToViewController = ToViewController()
 override func viewDidLoad() {
 super.viewDidLoad()
 setupView() // 关键是一些UI控制的合理布局,能够忽视实际上现关键点
 self.navigationController.delegate = self
}

与present/dismiss不一样的时,如今主视图操纵器完成的是UINavigationControllerDelegate协议书,让自身变成navigationController的代理商。这一协议书相近在此前的UIViewControllerTransitioningDelegate协议书。

FromViewController完成UINavigationControllerDelegate协议书的实际实际操作以下:

func navigationController(navigationController: UINavigationController, 
 animationControllerForOperation operation: UINavigationControllerOperation, 
 fromViewController fromVC: UIViewController, 
 toViewController toVC: UIViewController) 
 UIViewControllerAnimatedTransitioning? {
 if operation == .Push {
 return PushAnimator()
 if operation == .Pop {
 return PopAnimator()
 return nil;
 }

对于animator,就和先前沒有一切差别了。由此可见,一个封裝得非常好的animator,不但能在present/dismiss时应用,乃至还能够在push/pop时应用。

UINavigationController还可以加上互动式转换场地动漫,基本原理也和先前相近。

针对非互动式动漫,必须设定presentedViewController的transitioningDelegate特性,这一代理商必须为present和dismiss出示animator。在animator中要求了动漫的不断時间和主要表现逻辑性。

针对互动式动漫,必须在先前的基本上,由transitioningDelegate特性出示互动式动漫操纵器。在操纵器中开展恶性事件解决,随后升级动漫进行进展。

针对自定动漫,能够根据UIPresentationController中的四个涵数自定动漫实行前后左右的实际效果,能够改动presentedViewController的尺寸、外型并同歩实行别的的动漫。



联系我们

全国服务热线:4000-399-000 公司邮箱:343111187@qq.com

  工作日 9:00-18:00

关注我们

官网公众号

官网公众号

Copyright?2020 广州凡科互联网科技股份有限公司 版权所有 粤ICP备10235580号 客服热线 18720358503

技术支持:蒙版抠图