这是我的自定义Segue的代码
class FlipFromRightSegue: UIStoryboardSegue { override func perform() { let source:UIViewController = self.sourceViewController as UIViewController let destination:UIViewController = self.destinationViewController as UIViewController UIView.transitionWithView(source.view, duration: 1.0, options: .CurveEaseInOut | .TransitionFlipFromRight, animations: { () -> Void in source.view.addSubview(destination.view) }) { (finished) -> Void in destination.view.removeFromSuperview() source.presentViewController(destination, animated: false, completion: nil) } } }
我以为这可行,但实际上只有在执行segue后,视图才会改变。我应该怎么做才能使视图在中间出现“翻转”时发生变化?
提前致谢。
从iOS 7开始,我们通常不使用自定义序列为过渡设置动画。我们要么使用标准的模态演示,指定一个modalTransitionStyle(即,可以为模态过渡选择的一些动画的固定列表),要么实现自定义动画过渡。这两个描述如下:
modalTransitionStyle
如果要以编程方式执行此操作,则可以在目标控制器中的Swift 3中执行以下操作:
override func viewDidLoad() { super.viewDidLoad() modalTransitionStyle = .flipHorizontal // use `.FlipHorizontal` in Swift 2 }
然后,当您调用show/ showViewController或present/时presentViewController,演示将通过水平翻转进行。而且,当您关闭视图控制器时,动画会自动为您反转。
show
showViewController
present
presentViewController
modalPresentationStyle
.custom
class SecondViewController: UIViewController { let customTransitionDelegate = TransitioningDelegate() required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) modalPresentationStyle = .custom // use `.Custom` in Swift 2 transitioningDelegate = customTransitionDelegate } ...
}
这指定了UIViewControllerTransitioningDelegate将实例化动画控制器的。例如,在Swift 3中:
UIViewControllerTransitioningDelegate
class TransitioningDelegate: NSObject, UIViewControllerTransitioningDelegate { func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { return AnimationController(transitionType: .presenting) } func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { return AnimationController(transitionType: .dismissing) } }
动画控制器只是做.transitionFlipFromRight一个演示,或者.transitionFlipFromLeft在Swift 3中关闭:
.transitionFlipFromRight
.transitionFlipFromLeft
class AnimationController: NSObject, UIViewControllerAnimatedTransitioning { enum TransitionType { case presenting case dismissing } var animationTransitionOptions: UIViewAnimationOptions init(transitionType: TransitionType) { switch transitionType { case .presenting: animationTransitionOptions = .transitionFlipFromRight case .dismissing: animationTransitionOptions = .transitionFlipFromLeft } super.init() } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { //let inView = transitionContext.containerView let toView = transitionContext.viewController(forKey: .to)?.view let fromView = transitionContext.viewController(forKey: .from)?.view UIView.transition(from: fromView!, to: toView!, duration: transitionDuration(using: transitionContext), options: animationTransitionOptions.union(.curveEaseInOut)) { finished in transitionContext.completeTransition(true) } } func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 1.0 } }
有关iOS 7中引入的自定义过渡的更多信息,请参阅WWDC 2013视频使用视图控制器的自定义过渡。
AnimationController
transform(from:to:...)
因此,您真的想使用UIView.animateAPI 进行翻转动画。我很抱歉,因为以下内容涉及CATransform3D在关键帧动画中使用一些不直观的内容,但是会导致翻转动画,然后可以对其进行可取消的交互式过渡。
UIView.animate
CATransform3D
因此,在Swift 3中:
class AnimationController: NSObject, UIViewControllerAnimatedTransitioning { enum TransitionType { case presenting case dismissing } let transitionType: TransitionType init(transitionType: TransitionType) { self.transitionType = transitionType super.init() } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { let inView = transitionContext.containerView let toView = transitionContext.view(forKey: .to)! let fromView = transitionContext.view(forKey: .from)! var frame = inView.bounds func flipTransform(angle: CGFloat, offset: CGFloat = 0) -> CATransform3D { var transform = CATransform3DMakeTranslation(offset, 0, 0) transform.m34 = -1.0 / 1600 transform = CATransform3DRotate(transform, angle, 0, 1, 0) return transform } toView.frame = inView.bounds toView.alpha = 0 let transformFromStart: CATransform3D let transformFromEnd: CATransform3D let transformFromMiddle: CATransform3D let transformToStart: CATransform3D let transformToMiddle: CATransform3D let transformToEnd: CATransform3D switch transitionType { case .presenting: transformFromStart = flipTransform(angle: 0, offset: inView.bounds.size.width / 2) transformFromEnd = flipTransform(angle: -.pi, offset: inView.bounds.size.width / 2) transformFromMiddle = flipTransform(angle: -.pi / 2) transformToStart = flipTransform(angle: .pi, offset: -inView.bounds.size.width / 2) transformToMiddle = flipTransform(angle: .pi / 2) transformToEnd = flipTransform(angle: 0, offset: -inView.bounds.size.width / 2) toView.layer.anchorPoint = CGPoint(x: 0, y: 0.5) fromView.layer.anchorPoint = CGPoint(x: 1, y: 0.5) case .dismissing: transformFromStart = flipTransform(angle: 0, offset: -inView.bounds.size.width / 2) transformFromEnd = flipTransform(angle: .pi, offset: -inView.bounds.size.width / 2) transformFromMiddle = flipTransform(angle: .pi / 2) transformToStart = flipTransform(angle: -.pi, offset: inView.bounds.size.width / 2) transformToMiddle = flipTransform(angle: -.pi / 2) transformToEnd = flipTransform(angle: 0, offset: inView.bounds.size.width / 2) toView.layer.anchorPoint = CGPoint(x: 1, y: 0.5) fromView.layer.anchorPoint = CGPoint(x: 0, y: 0.5) } toView.layer.transform = transformToStart fromView.layer.transform = transformFromStart inView.addSubview(toView) UIView.animateKeyframes(withDuration: self.transitionDuration(using: transitionContext), delay: 0, options: [], animations: { UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.0) { toView.alpha = 0 fromView.alpha = 1 } UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.5) { toView.layer.transform = transformToMiddle fromView.layer.transform = transformFromMiddle } UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.0) { toView.alpha = 1 fromView.alpha = 0 } UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5) { toView.layer.transform = transformToEnd fromView.layer.transform = transformFromEnd } }, completion: { finished in toView.layer.transform = CATransform3DIdentity fromView.layer.transform = CATransform3DIdentity toView.layer.anchorPoint = CGPoint(x: 0.5, y: 0.5) fromView.layer.anchorPoint = CGPoint(x: 0.5, y: 0.5) transitionContext.completeTransition(!transitionContext.transitionWasCancelled) }) } func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 1.0 } }
无论如何,如果在过渡结束时不再可见“ from”视图,则应指示演示控制器将其从视图层次结构中删除,例如:
class PresentationController: UIPresentationController { override var shouldRemovePresentersView: Bool { return true } }
而且,显然,您必须TransitioningDelegate将此演示控制器通知您:
TransitioningDelegate
class TransitioningDelegate: NSObject, UIViewControllerTransitioningDelegate { ... func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { return PresentationController(presentedViewController: presented, presenting: presenting) } }
此答案已针对Swift 3进行了更新。