如何创建自定义View Controller过渡和动画

介绍

UIKit是一个非常强大的框架,并提供了在视图控制器之间进行转换的各种方法。 UIKit提供的一些动画包括水平滑动(通过推键),垂直滑动,交叉淡入淡出和页面卷曲。 但是,有时候,您需要在视图控制器之间进行自定义过渡,以创建引人注目的设计或提供独特的用户体验。 自定义转换的一个很好的例子是选择照片时使用Apple的iOS照片。

在本教程中,我将向您展示如何通过使用多个UIKit API创建自己的自定义过渡。

要求

在iOS 7中引入了用于创建自定义过渡的API时,本教程使用了Auto Layout和Swift 2,这意味着您需要在OS X Yosemite或更高版本上运行Xcode 7+。 您还需要从GitHub下载入门项目。

1.自定义过渡的组成部分

实施自定义视图控制器转换时,需要注意两个主要组件:

  • 动画控制器 ,也称为动画器
  • 过渡委托 ,您分配的视图控制器

动画师对象负责为视图制作动画的持续时间和实际逻辑。 您的应用中的动画控制器可以是任何类型的对象,只要它符合UIViewControllerAnimatedTransitioning协议即可。

过渡委托负责提供用于自定义过渡的动画控制器。 您指定的委托对象必须符合UIViewControllerTransitioningDelegate协议。

2.创建自定义过渡

打开入门项目并运行您的应用程序。 当您点击“ 按查看”按钮时,当前正在使用标准的垂直模式过渡。

通过从“ 文件”菜单中选择“ 新建”>“文件...”来创建一个新文件。 从显示的选项中,选择“ iOS”>“源”>“ Swift 文件” ,并将文件命名为CustomTransition 。 该文件将保留自定义转换所需的逻辑。

首先,我们将定义将用于自定义过渡的动画控制器类。 将以下代码添加到CustomTransition.swift中

import UIKit

enum TransitionType {
    case Presenting, Dismissing
}

class AnimationController: NSObject, UIViewControllerAnimatedTransitioning {
    var duration: NSTimeInterval
    var isPresenting: Bool
    var originFrame: CGRect
    
    init(withDuration duration: NSTimeInterval, forTransitionType type: TransitionType, originFrame: CGRect) {
        self.duration = duration
        self.isPresenting = type == .Presenting
        self.originFrame = originFrame
        
        super.init()
    }
    
    func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
        return self.duration
    }
}

我们定义了TransitionType枚举,该枚举在创建AnimationController对象时使用。

接下来,我们定义带有一些属性的AnimationController类。 duration属性将用于确定动画的持续时间,并且是UIViewControllerAnimatedTransitioning协议方法transitionDuration(_:)返回的值。 该持续时间不必是变量,但是在创建动画控制器时仅设置一次即可更改。 isPresentingoriginFrame属性都将用于创建过渡的动画。

此时,Xcode应该会向您显示错误。 这是因为我们尚未实现UIViewControllerAnimatedTransitioning协议的必需方法。 在实现此方法之前,您需要了解一件事。

自定义过渡开始时,UIKit将为您提供一个容器视图,您必须在其中执行过渡的动画。 在此容器视图中,您必须手动添加要转换到的视图控制器的视图。 此容器视图仅在过渡期间有效,并且动画完成后立即从视图层次结构中删除。

现在,我们将实现自定义动画。 将以下方法添加到AnimationController类中:

func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
    let containerView = transitionContext.containerView()!
    
    let fromView = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!.view
    let toView = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!.view
    
    let detailView = self.isPresenting ? toView : fromView
    
    if self.isPresenting {
        containerView.addSubview(toView)
    } else {
        containerView.insertSubview(toView, belowSubview: fromView)
    }
    
    detailView.frame.origin = self.isPresenting ? self.originFrame.origin : CGPoint(x: 0, y: 0)
    detailView.frame.size.width = self.isPresenting ? self.originFrame.size.width : containerView.bounds.width
    detailView.layoutIfNeeded()
    
    for view in detailView.subviews {
        if !(view is UIImageView) {
            view.alpha = isPresenting ? 0.0 : 1.0
        }
    }
    
    UIView.animateWithDuration(self.duration, animations: { () -> Void in
        detailView.frame = self.isPresenting ? containerView.bounds : self.originFrame
        detailView.layoutIfNeeded()
        
        for view in detailView.subviews {
            if !(view is UIImageView) {
                view.alpha = self.isPresenting ? 1.0 : 0.0
            }
        }
    }) { (completed: Bool) -> Void in
        transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
    }
}

我们通过使用containerView()方法从提供的过渡上下文中检索容器视图来开始此方法。 我们通过调用viewControllerForKey(_:)方法viewControllerForKey(_:)分别传入UITransitionContextFromViewControllerKeyUITransitionContextToViewControllerKey 访问fromto视图。

在iOS 8及更高版本中,您可以使用viewForKey(_:)方法以及UITransitionContextFromViewKeyUITransitionContextToViewKey键直接访问视图。

在方法主体中,我们使用现有的UIView动画API对细节视图进行动画处理,以增大或缩小。

要注意的最后一件事是在过渡上下文对象上调用的completeTransition(_:)方法。 动画完成后必须调用此方法,以使系统知道您的视图控制器已完成转换。 此方法接受布尔值作为其单个参数,该布尔值指示转换是否完成。

通过此实现,我们创建了一个功能齐全的动画控制器。 为了实际实现这一点,我们现在需要设置一个过渡委托。

3.分配过渡代表

如前所述, 过渡委托的工作是为两个视图控制器之间的过渡提供动画控制器对象。 过渡的委托可以是您想要的任何对象,但是通常的做法是使呈现视图控制器成为委托。

CustomTransition.swift中 ,在AnimationController类定义下面添加以下代码:

extension ViewController: UIViewControllerTransitioningDelegate {
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        segue.destinationViewController.transitioningDelegate = self
    }
    
    func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return AnimationController(withDuration: 3.0, forTransitionType: .Dismissing, originFrame: self.image.frame)
    }
    
    func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return AnimationController(withDuration: 3.0, forTransitionType: .Presenting, originFrame: self.image.frame)
    }
}

通过实现此扩展,我们使ViewController类符合UIViewControllerTransitioningDelegate协议并实现三种方法。 首先, prepareForSegue(_:sender:)用于将当前ViewController实例指定为目标DetailViewController对象的transitioningDelegate 。 另外两个方法创建一个AnimationController对象,以使用我们之前定义的初始化程序来呈现和消除视图控制器。 如果您从这两种方法中的任何一个返回nil ,则将使用默认或标准视图控制器转换。

设置了过渡委托后,就可以构建和运行您的应用了。 这次,当您点击“ 按一下查看”按钮时,您应该看到Xcode图标的大小增加了,其他标签逐渐淡入。同样,当您点击“ 按一下关闭”按钮时,您应该看到相同的动画,但相反。

自定义过渡

恭喜你 现在,您已经在iOS上成功创建了第一个自定义视图控制器转换。

4.使过渡互动

为了使自定义过渡更好,我们将使其具有交互性和响应性。 一个很好的例子是UINavigationController从左边缘向后滑动手势。

要使自定义过渡具有交互性,首先需要具有一个符合UIViewControllerInteractiveTransitioning协议的对象。 在本教程中,我们将使用UIKit提供的已经符合该协议的类UIPercentDrivenInteractiveTransition

为了在视图控制器之间轻松进行通信(过渡委托和视图控制器确定过渡完成的百分比),请打开DetailViewController.swift并将以下属性添加到DetailViewController类中:

var rootViewController: ViewController!

接下来,将以下代码添加到DetailViewController类的didPanDown(_:)方法中:

@IBAction func didPanDown(sender: UIPanGestureRecognizer) {
    let progress = sender.translationInView(self.view).y/self.view.frame.size.height

    switch sender.state {
    case .Began:
        self.rootViewController.interactionController = UIPercentDrivenInteractiveTransition()
        self.dismissViewControllerAnimated(true, completion: nil)
    case .Changed:
        self.rootViewController.interactionController?.updateInteractiveTransition(progress)
    case .Ended:
        if progress >= 0.5 {
            self.rootViewController.interactionController?.finishInteractiveTransition()
        } else {
            self.rootViewController.interactionController?.cancelInteractiveTransition()
        }

        self.rootViewController.interactionController = nil
    default:
        self.rootViewController.interactionController?.cancelInteractiveTransition()
        self.rootViewController.interactionController = nil
    }
}

didPanDown(_:)方法中,我们根据用户相对于详细视图的平移程度来计算progress变量的值。 如果平移刚开始,我们将创建交互控制器对象,然后开始关闭视图控制器。 每当平移手势在视图中移动时,我们都会向交互控制器更新过渡应该进行的距离。

最后,当平移结束时,我们分别使用finishInteractiveTransition()cancelInteractiveTransition()方法完成或取消过渡。

接下来,返回CustomTransition.swift并将ViewController类扩展中的prepareForSegue(_:sender:)方法替换为以下内容:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    segue.destinationViewController.transitioningDelegate = self
    (segue.destinationViewController as? DetailViewController)?.rootViewController = self
}

prepareForSegue(_:sender:) ,我们授予详细视图控制器对根视图控制器的访问权限。

最后,将以下方法添加到ViewController扩展中:

func interactionControllerForDismissal(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
    return self.interactionController
}

interactionControllerForDismissal(_:)方法返回根视图控制器的interactionController 。 如果为nil (例如,如果轻按了按钮),则将改用自定义动画。

如您所料,通过实现interactionControllerForPresentation(_:)方法,在呈现视图控制器时也可以使用交互式控制器。

上一次构建并运行您的应用程序,并在显示详细视图控制器之后,在屏幕上向下拖动,您将看到过渡与手指位置同步移动。

结论

现在,您应该可以轻松地在iOS上创建完全交互式的自定义视图控制器过渡。 如您所见,这些API仅受UIKit和Core Animation的动画功能阻碍。 它们几乎可以用于任何类型的转换。 与往常一样,在下面的评论中留下您的评论和反馈。

翻译自: https://code.tutsplus.com/tutorials/how-to-create-custom-view-controller-transitions-and-animations--cms-25716

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值