- 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时视图才会改变.当“翻转”位于中间时,我该怎么做才能使视图发生变化?
提前致谢.
>如果您只是呈现另一个视图控制器的视图,则将动画更改为翻转的简单解决方案是在目标视图控制器中设置modalTransitionStyle.您可以在segue的属性下完全在Interface Builder中完成此操作.
如果您想以编程方式执行此操作,则可以在目标控制器中在Swift 3中执行以下操作:
- override func viewDidLoad() {
- super.viewDidLoad()
- modalTransitionStyle = .flipHorizontal // use `.FlipHorizontal` in Swift 2
- }
然后,当您调用show / showViewController或present / presentViewController时,您的演示文稿将以水平翻转方式执行.并且,当您关闭视图控制器时,动画会自动反转.
>如果您需要更多控制,在iOS 7及更高版本中,您将使用自定义动画过渡,您可以在其中指定.custom的modalPresentationStyle.例如,在Swift 3中:
- 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中:
- 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中被解雇:
- 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视频Custom Transitions Using View Controllers.
>如果应该承认上面的AnimationController实际上是一个过度简化,因为我们正在使用transform(from:to:…).这会导致动画无法取消(如果您正在使用交互式过渡).它也删除了“从”视图本身,从iOS 8开始,现在它实际上是演示控制器的工作.
所以,你真的想用UIView.animate API做翻转动画.我很抱歉,因为以下内容涉及在关键帧动画中使用一些不直观的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)
- transform.m34 = -1.0 / 1600
- transform = CATransform3DRotate(transform,angle,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
- }
- }
>仅供参考,iOS 8通过演示控制器扩展了自定义转换模型.有关更多信息,请参阅WWDC 2014视频A Look Inside Presentation Controllers.
无论如何,如果在转换结束时,“from”视图不再可见,您将指示您的演示控制器将其从视图层次结构中删除,例如:
- class PresentationController: UIPresentationController {
- override var shouldRemovePresentersView: Bool { return true }
- }
显然,你必须通知你的TransitioningDelegate这个演示控制器:
- class TransitioningDelegate: NSObject,UIViewControllerTransitioningDelegate {
- ...
- func presentationController(forPresented presented: UIViewController,presenting: UIViewController?,source: UIViewController) -> UIPresentationController? {
- return PresentationController(presentedViewController: presented,presenting: presenting)
- }
- }
此答案已针对Swift 3进行了更新.如果您想查看Swift 2实现,请参阅previous revision of this answer.