是否可以在故事板中的视图控制器之间进行淡入和淡出过渡。或者没有过渡。
如果可以的话,代码是什么?
modalTransitionStyle
或 UIModalTransitionStyleCrossDissolve
。如果在故事板中使用 Segue 执行此操作,请选择 Segue 的属性检查器,并在其中指定过渡样式:
如果以编程方式呈现视图控制器,您可以使用“交叉溶解”的“过渡”在故事板中的视图控制器之间定义模态转场,然后让源视图控制器执行此转场:
[self performSegueWithIdentifier:@"presentSegue" sender:sender];
或者,如果您打电话
presentViewController
:
UIViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:@"YourStoryboardID"];
controller.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:controller animated:YES completion:nil];
在 iOS 7 中,Apple 提供了一项新技术,可以为高度定制的过渡提供丰富而强大的控制。有关更多信息,请参阅 WWDC 2013 视频使用视图控制器自定义过渡。
但是,例如,如果您想在 iOS 7 中自定义推送和弹出动画以淡入淡出,则可以为导航控制器指定
delegate
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationController.delegate = self;
}
然后您将实现
animationControllerForOperation
,指定用于推送和弹出的动画对象:
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController*)fromVC
toViewController:(UIViewController*)toVC
{
if (operation == UINavigationControllerOperationPush)
return [[PushAnimator alloc] init];
if (operation == UINavigationControllerOperationPop)
return [[PopAnimator alloc] init];
return nil;
}
您显然必须实现自定义的推送和弹出动画师,例如:
@interface PushAnimator : NSObject <UIViewControllerAnimatedTransitioning>
@end
@implementation PushAnimator
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
{
return 0.5;
}
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
[[transitionContext containerView] addSubview:toViewController.view];
toViewController.view.alpha = 0.0;
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
toViewController.view.alpha = 1.0;
} completion:^(BOOL finished) {
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
@end
还有
@interface PopAnimator : NSObject <UIViewControllerAnimatedTransitioning>
@end
@implementation PopAnimator
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
{
return 0.5;
}
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
[[transitionContext containerView] insertSubview:toViewController.view belowSubview:fromViewController.view];
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
fromViewController.view.alpha = 0.0;
} completion:^(BOOL finished) {
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
@end
还有一种类似但略有不同的技术用于自定义模式转换(尽管如果您只是做一张脸,您可能只会使用上面讨论的
modalTransitionStyle
,除非您想使用其他一些微妙的自定义) 。有关更多信息,请参阅前面提到的使用视图控制器自定义转换。
底线,iOS 7 的自定义过渡是一种稍微复杂但非常强大的方法,可以对过渡动画提供巨大的控制。
为了创建自定义 Segue,请创建 UIStoryboard segue 的子类。 例如:
// MCFadeSegue.h
#import <UIKit/UIKit.h>
@interface MCFadeSegue : UIStoryboardSegue
@end
// MCFadeSegue.m
#import <QuartzCore/QuartzCore.h>
#import "MCFadeSegue.h"
@implementation MCFadeSegue
- (void)perform
{
CATransition *transition = [CATransition animation];
transition.duration = 0.5;
transition.type = kCATransitionFade;
[[[[[self sourceViewController] view] window] layer] addAnimation:transition
forKey:kCATransitionFade];
[[self sourceViewController]
presentViewController:[self destinationViewController]
animated:NO completion:NULL];
}
@end
然后在MainStoryboard.storyboard中选择segue并设置Style:Custom和Class:MCFadeSegue。
Swift 中的推送/弹出 UIVIewController 淡入/淡出
class FadeInPushSegue: UIStoryboardSegue {
var animated: Bool = true
override func perform() {
if var sourceViewController = self.sourceViewController as? UIViewController, var destinationViewController = self.destinationViewController as? UIViewController {
var transition: CATransition = CATransition()
transition.type = kCATransitionFade; //kCATransitionMoveIn; //, kCATransitionPush, kCATransitionReveal, kCATransitionFade
sourceViewController.view.window?.layer.addAnimation(transition, forKey: "kCATransition")
sourceViewController.navigationController?.pushViewController(destinationViewController, animated: false)
}
}
}
class FadeOutPopSegue: UIStoryboardSegue {
override func perform() {
if var sourceViewController = self.sourceViewController as? UIViewController, var destinationViewController = self.destinationViewController as? UIViewController {
var transition: CATransition = CATransition()
transition.duration = 0.4
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.type = kCATransitionFade; //kCATransitionMoveIn; //, kCATransitionPush, kCATransitionReveal, kCATransitionFade
sourceViewController.view.window?.layer.addAnimation(transition, forKey: "kCATransition")
sourceViewController.navigationController?.popViewControllerAnimated(false)
}
}
}
试试这个。
let transition: CATransition = CATransition()
transition.duration = 0.4
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.type = kCATransitionFade
self.navigationController!.view.layer.addAnimation(transition, forKey: nil)
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("vcID") as! My_ViewController
self.navigationController?.pushViewController(vc, animated: false)
无需创建自定义 Segue,我就可以将这段代码放在一起来呈现视图...
UIViewController *nextView = [[UIStoryboardstoryboardWithName:@"Main"bundle:nil] instantiateViewControllerWithIdentifier:@"YOUR_VIEW_CONTROLLER_STORYBOARD_NAME"]; nextView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; [self.navigationController PresentViewController:nextView 动画:YES 完成:nil]; //(对于交叉溶解,设置动画:YES。对于无过渡,设置动画:NO。)
希望这对遇到这个问题的人有所帮助!
我的 Swift 版本当然带有可选检查!
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
if let stView = storyboard.instantiateViewControllerWithIdentifier("STVC") as? STVC {
stView.modalTransitionStyle = UIModalTransitionStyle.CrossDissolve
self.navigationController?.presentViewController(stView, animated: true, completion: nil)
}
只需确保在IB中设置“视图控制器”的Storyboard ID即可
Swift 3语法中的Push/Pop UIVIewController FadeIn/FadeOut,基于Eugene Braginets的answer
class FadeInPushSegue: UIStoryboardSegue {
var animated: Bool = true
override func perform() {
let sourceViewController = self.source
let destinationViewController = self.destination
let transition: CATransition = CATransition()
transition.type = kCATransitionFade; //kCATransitionMoveIn; //, kCATransitionPush, kCATransitionReveal, kCATransitionFade
sourceViewController.view.window?.layer.add(transition, forKey: "kCATransition")
sourceViewController.navigationController?.pushViewController(destinationViewController, animated: false)
}
}
class FadeOutPopSegue: UIStoryboardSegue {
override func perform() {
let sourceViewController = self.source
let transition: CATransition = CATransition()
transition.duration = 0.4
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.type = kCATransitionFade; //kCATransitionMoveIn; //, kCATransitionPush, kCATransitionReveal, kCATransitionFade
sourceViewController.view.window?.layer.add(transition, forKey: "kCATransition")
_ = sourceViewController.navigationController?.popViewController(animated: false)
}
}
斯威夫特5:
花了几个小时寻找正确的解决方案后Rob的解决方案满足了我的所有需求,经过一些调整后它是完美的。
创建淡入淡出视图控制器类:
class FadeViewControllerTransition: NSObject, UIViewControllerAnimatedTransitioning {
var fadeOut: Bool = false
func transitionDuration(
using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.5
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
if fadeOut {
animateFadeOut(using: transitionContext)
return
}
let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!
transitionContext.containerView.addSubview(toViewController.view)
toViewController.view.alpha = 0.0
UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: {
toViewController.view.alpha = 1.0
}, completion: { _ in
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
})
}
func animateFadeOut(using transitionContext: UIViewControllerContextTransitioning) {
let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!
let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!
transitionContext.containerView.insertSubview(toViewController.view, belowSubview: fromViewController.view)
UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: {
fromViewController.view.alpha = 0.0
}, completion: { _ in
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
})
}
}
在导航控制器的第一个视图控制器中:
class MainViewController: UIViewController, UIViewControllerTransitioningDelegate, UINavigationControllerDelegate {
private let fadeVCTransition = FadeViewControllerTransition()
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
fadeVCTransition.fadeOut = (operation == .pop)
return fadeVCTransition
}
就是这样。
这让我彻底抓狂了好几个小时。这些解决方案似乎都不是我想要的,我快要失去理智了。最后提出了以下方案,它使用淡出/淡入过渡在单个 NSWindow 内交换视图控制器。首先它执行淡出,然后在完成处理程序中,它将窗口的视图设置为新视图并执行淡入。也许有更好的方法来做到这一点,但这是我可以一起破解的最简单方法.
class CustomSegue : NSStoryboardSegue {
override func perform() {
guard let fromController = sourceController as? NSViewController else {
return;
}
guard let toController = destinationController as? NSViewController else {
return;
}
let animationDuration = 0.5;
NSAnimationContext.runAnimationGroup({
$0.duration = animationDuration;
fromController.view.animator().alphaValue = 0.0;
}, completionHandler: {
fromController.view.window?.contentViewController = toController;
toController.view.alphaValue = 0.0;
NSAnimationContext.runAnimationGroup({
$0.duration = animationDuration;
toController.view.animator().alphaValue = 1.0;
})
});
}
}
Apple 文档中缺乏示例让我想破脑袋,而 Objective C 和 Swift 无处不在的混合只是......呸!
无需过渡即可呈现:
我想向
extension
提出一个UINavigationController
,这是基于@Soumya Ranjan的回答:
extension UINavigationController {
func addTransition(duration: CFTimeInterval = 0.25,
timingFunctionName: CAMediaTimingFunctionName = .easeInEaseOut,
type: CATransitionType = .fade,
forKey key: String? = nil) {
let transition = CATransition()
transition.duration = duration
transition.timingFunction = CAMediaTimingFunction(name: timingFunctionName)
transition.type = type
view.layer.add(transition, forKey: key)
}
}
用途: 在设置/推送新控制器进行导航之前,请务必致电
addTransition()
。
重要提示: 设置/推送
animated:
参数设置为 false
let viewController = UIViewController()
let navigationController = UINavigationController()
navigationController.addTransition() // <--- HERE
navigationController.setViewControllers([viewController], animated: false) // <--- HERE
也可以随意提供自定义参数:
navigationController.addTransition(
duration: 0.4,
timingFunctionName: .linear,
type: .reveal,
forKey: "CustomTransitionKey"
)