目录
二、视图切换定制
2.1 基础说明
要创建定制切换效果,你需要做如下的事情:
- 创建一个类来实现
UIViewControllerAnimatedTransitioning
协议。在这个类中将编写代码来执行动画,这个类将作为动画控制器被关联。 - 在呈现一个视图控制器之前,设置一个类作为它的切换效果委托。这个委托将为动画控制器获取一个回调方法,这个回调方法用于视图控制器的呈现。
- 实现回调方法来返回一个在第一步创建的动画控制器的实例。
2.1.1 UIViewControllerAnimatedTransitioning
协议
UIViewControllerAnimatedTransitioning
协议用于描述视图控制器切换的动画效果,我们可以通过实现这个协议,并利用该类来实现在视图间切换过程中的动画效果。可以在这个类中定义一个动画对象,这个动画对象创建一个视图控制器在一个固定的时间内出现/消失在屏幕上的动画效果。使用这个协议创建的动画 必须 是无法交互的。如果要创建可以交互的切换,必须混合动画对象和另一个控制动画时间的对象。
在动画对象中,实现transitionDuration:
方法来指定切换的过程,实现animateTransition:
方法来创建动画。在切换过程中使用的对象的信息在一个上下文对象中传递给animateTransition:
方法。使用这个上下文对象(UIViewControllerContextTransitioning
)提供的信息,来移动目标视图控制器的视图在指定的区间内出现/消失在屏幕上。
从一个实现了UIViewControllerTransitioningDelegate
协议的切换委托对象中创建一个动画对象。当呈现一个视图控制器时,设置呈现类型为UIModalPresentationCustom
,并指定切换委托到视图控制器的transitioningDelegate
属性。视图控制器从切换委托中接受动画对象,并使用这个切换委托来执行动画。可以为视图控制器的出现、消失分别定制不同的动画对象。
为了添加用户交互到一个视图控制器的切换效果中,必须一起使用一个动画对象和一个交互动画对象(一个实现UIViewControllerInteractiveTransitioning
协议的定制类)。
执行切换
切换过程:
具体实现如下所示。
import Foundation
import UIKit
class AnimatedTransitioning: NSObject, UIViewControllerAnimatedTransitioning {
func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
return 5
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
let finalFrameForVC = transitionContext.finalFrameForViewController(toViewController)
let containerView = transitionContext.containerView()
let bounds = UIScreen.mainScreen().bounds
toViewController.view.frame = CGRectOffset(finalFrameForVC, 0, bounds.size.height)
containerView.addSubview(toViewController.view)
UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.0, options: .CurveLinear, animations: {
fromViewController.view.alpha = 0.5
toViewController.view.frame = finalFrameForVC
}, completion: {
finished in
transitionContext.completeTransition(true)
fromViewController.view.alpha = 1.0
})
}
}
2.1.2 UIViewControllerTransitioningDelegate
import UIKit
class ViewController: UIViewController, UIViewControllerTransitioningDelegate {
// ...
let customPresentAnimationController = CustomPresentAnimationController()
let customDismissAnimationController = CustomDismissAnimationController()
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showAction" {
let toViewController = segue.destinationViewController as! UIViewController
// 用于给目标视图指定切换动画代理
toViewController.transitioningDelegate = self
}
}
// 用于视图出现
func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return customPresentAnimationController
}
// 用于视图消失
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return customDismissAnimationController
}
// ...
}
2.1.3 UIViewControllerInteractiveTransitioning
注意:
UIPercentDrivenInteractiveTransition
是UIViewControllerInteractiveTransitioning
的子类
import UIKit
class CustomInteractionController: UIPercentDrivenInteractiveTransition {
var navigationController: UINavigationController!
var shouldCompleteTransition = false
var transitionInProgress = false
var completionSeed: CGFloat {
return 1 - percentComplete
}
func attachToViewController(viewController: UIViewController) {
navigationController = viewController.navigationController
setupGestureRecognizer(viewController.view)
}
private func setupGestureRecognizer(view: UIView) {
view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: "handlePanGesture:"))
}
func handlePanGesture(gestureRecognizer: UIPanGestureRecognizer) {
let viewTranslation = gestureRecognizer.translationInView(gestureRecognizer.view!.superview!)
switch gestureRecognizer.state {
case .Began:
transitionInProgress = true
navigationController.popViewControllerAnimated(true)
case .Changed:
var const = CGFloat(fminf(fmaxf(Float(viewTranslation.x / 200.0), 0.0), 1.0))
shouldCompleteTransition = const > 0.5
updateInteractiveTransition(const)
case .Cancelled, .Ended:
transitionInProgress = false
if !shouldCompleteTransition || gestureRecognizer.state == .Cancelled {
cancelInteractiveTransition()
} else {
finishInteractiveTransition()
}
default:
println("Swift switch must be exhaustive, thus the default")
}
}
}
2.1.4 UIViewControllerContextTransitioning
UIViewControllerContextTransitioning
协议的方法为切换的两个视图控制器提供上下文信息。在一次切换当中,切换中使用的动画对象从UIKit
接受一个完整的配置上下文对象,UIViewControllerAnimatorTransitioning
或UIViewControllerInteractiveTransitioning
协议的方法从提供的对象中提取它们需要的信息。
访问切换对象
containerView()
:获取在动画执行过程中作为父视图的视图。viewControllerForKey(_:)
:Key可选值参数见下方的__常量__部分。viewForKey(_:)
获取切换框体矩形
finalFrameForViewController
用于获取指定的视图控制器视图最终的框体矩形。
获取切换行为
反馈切换进度
completeTransition(_:)
必须updateInteractiveTransition(_:)
必须finishInteractiveTransition()
必须cancelInteractiveTransition()
必须transitionWasCancelled()
必须
获取屏幕方向
常量
View Controller Transition Keys
用于标识在切换执行过程中所存在的视图控制器,包含两个值,一个是UITransitionContextFromViewControllerKey
用于标识在动画开始时就已经存在的视图控制器,一个是UITransitionContextToViewControllerKey
用于标识在动画完成后应该存在的视图控制器。
View Transition Keys
用于标识在切换执行过程中所存在的视图,包含两个值,一个是UITransitionContextFromViewKey
用于标识在动画开始时就已经存在的视图,一个是UITransitionContextToViewKey
用于标识在动画完成后应该存在的视图。
来源:oschina
链接:https://my.oschina.net/u/96756/blog/491596