在iOS 7中,当推送视图到UINavigationController时,我该如何进行交叉溶解?

24

如果我只是简单地调用push方法,并传入:

[self.navigationController pushViewController:viewController animated:YES];

然后它使用一个推送动画。我怎样才能将其更改为使用交叉溶解动画,就像我可以使用模态分界线一样?

7个回答

31

我使用一个扩展程序以便轻松地进行重复利用:

extension UINavigationController {
    func fadeTo(_ viewController: UIViewController) {
        let transition: CATransition = CATransition()
        transition.duration = 0.3
        transition.type = CATransitionType.fade
        view.layer.add(transition, forKey: nil)
        pushViewController(viewController, animated: false)
    }
}

注意动画属性为false;当你将其设置为true时,你仍然会看到标准的“推”动画(从右到左)。


1
这确实是最简单和最快的解决方案! - Gargo

25

您可以使用CATransition,如此答案所示:

CATransition* transition = [CATransition animation];
transition.duration = 0.5;
transition.type = kCATransitionFade;
[self.navigationController.view.layer addAnimation:transition forKey:nil];
[self.navigationController pushViewController:viewController animated:NO];

1
这并不完全相同。它会消失,但仍然看起来像是滑入。 - BennyTheNerd
4
如果你将animated设置为NO,滑动(推动)动画将被禁用,因此它会按预期工作。 - David

16

UINavigationControllerDelegate协议有一个方法,可以返回一个自定义的UIViewControllerAnimatedTransitioning对象,该对象将控制涉及过渡的两个视图控制器之间的动画。

创建一个名为Animator的类以控制交叉溶解过渡:

class Animator: NSObject, UIViewControllerAnimatedTransitioning {
    
    let animationDuration = 0.25
    
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return animationDuration
    }
    
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        let toVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)
        toVC?.view.alpha = 0.0
        let fromVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)
        transitionContext.containerView.addSubview(fromVC!.view)
        transitionContext.containerView.addSubview(toVC!.view)
    
        UIView.animate(withDuration: animationDuration, animations: {
            toVC?.view.alpha = 1.0
        }) { (completed) in
            fromVC?.view.removeFromSuperview()
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        }
    }
}

并在您的UINavigationControllerDelegate中提供它:

func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    return Animator()
}

这里有一篇更深入的教程:https://web.archive.org/web/20191204115047/http://blog.rinatkhanov.me/ios/transitions.html


2
感谢提供一个高级别(非核心图形)的方法。不过,fromVC?.view.removeFromSuperview() 让我很困扰。我已经解决了这个问题:在返回转换时,演示者的视图可以预测地为空白。 - Anton Tropashko
containerView中添加fromVC!.view并不是必须的。相关文章似乎证实了这一说法。 - Iulian Onofrei

9

SWIFT 3, 4.2 -- as of October, 2019

let transition = CATransition()
transition.duration = 0.5
transition.type = kCATransitionFade
self.navigationController?.view.layer.add(transition, forKey:nil)

您还需要在 pushViewController 中将 animated 设置为 false,对吗? - Crashalot
不,不是这样的。如果你想要“淡入”效果,你必须将animated设置为false - Mateusz
Animated设置为true是正确的做法=) - BennyTheNerd
@BennyTheNerd 不对,必须将animated设置为false,就像Mateusz提到的那样。 - Gustavo Baiocchi Costa

3
你可以像这样设置Push视图控制器。
        CATransition* transition = [CATransition animation];
        transition.duration = 0.4;
        transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
        transition.type = kCATransitionFade;
        [self.navigationController.view.layer addAnimation:transition forKey:@"kCATransition"];
        [self.navigationController pushViewController:readerViewController animated:false];

您可以像这样设置弹出视图控制器。
         CATransition* transition = [CATransition animation];
         transition.duration = 0.4;
         transition.timingFunction = [CAMediaTimingFunction 
         functionWithName:kCAMediaTimingFunctionEaseOut];
         transition.type = kCATransitionFade;
         [self.navigationController.view.layer addAnimation:transition 
          forKey:@"kCATransition"];
         [self.navigationController popViewControllerAnimated:false];

3

更新 Swift 5

使用prepare(for segue:)替代pushViewController:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    // other preparations

    let transition: CATransition = CATransition()
    transition.duration = 0.3
    transition.type = CATransitionType.fade
    navigationController?.view.layer.add(transition, forKey: nil)
}

非常好的简单解决方案。谢谢。 - mtl

0

根据michaels的回答,您可以使用UINavigationController扩展...就像这样

/// Create an animatied fade push with default duration time.
/// - Parameters:
///   - controller: Which controller are we pushing...?
///   - animationDuration: What's the animation duration - has a default
func pushViewControllerWithFade(_ controller: UIViewController, animationDuration: TimeInterval = .Animation.defaultAnimationTime) {
    let transition: CATransition = .init()
    transition.duration = animationDuration
    transition.type = .fade
    pushViewController(controller, withTransition: transition)
}

/// Custom transition animation for pushing view contorller
/// - Parameters:
///   - controller: Which controller are we presenting now?
///   - transition: The transition for the push animation
func pushViewController(_ controller: UIViewController, withTransition transition: CATransition) {
    view.layer.add(transition, forKey: nil)
    pushViewController(controller, animated: false)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接