objective-c 恢复 iOS7 之前的 UINavigationController pushViewController 动画
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18867248/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Restore pre-iOS7 UINavigationController pushViewController animation
提问by Bart van den Berg
So. Just started transitioning my IOS code to IOS7, and ran into a bit of problem.
所以。刚开始将我的 IOS 代码转换为 IOS7,遇到了一些问题。
I've got a UINavigationController, which has child ViewControllers and I'm using pushViewControllerto display the next views. To create a parallax animation with a set of images, if customized the UINavigationControllerto animate a set of UIImageViewsand my child ViewControllers all have a self.backgroundColor = [UIColor clearColor], transparency.
我有一个UINavigationController,它有子 ViewControllers,我pushViewController用来显示下一个视图。要使用一组图像创建视差动画,如果自定义为一组图像UINavigationController设置动画,UIImageViews并且我的子视图控制器都具有self.backgroundColor = [UIColor clearColor], 透明度。
Since iOS7, the way the UINavControlleranimates it child vc's, is updated, by partially moving the current view controller and on top pushing the new viewcontroller, my parallax animation looks crap. I see the previous VC move a bit and then disappear. Is there any way I can restore the previous UINavigationControllerpushViewController animation? I can't seem to find this in the code.
从 iOS7 开始,UINavController通过部分移动当前视图控制器并在顶部推动新的视图控制器,更新子 vc 的动画方式,我的视差动画看起来很糟糕。我看到之前的 VC 移动了一点然后消失了。有什么办法可以恢复以前的UINavigationControllerpushViewController 动画吗?我似乎无法在代码中找到它。
WelcomeLoginViewController* welcomeLoginViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"WelcomeLogin"];
[self.navigationController pushViewController:welcomeLoginViewController animated:YES];
Even tried using:
甚至尝试使用:
[UIView animateWithDuration:0.75
animations:^{
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[self.navigationController pushViewController:welcomeLoginViewController animated:NO];
[UIView setAnimationTransition:<specific_animation_form> forView:self.navigationController.view cache:NO];
}];
Does anyone have any clue?
有没有人有任何线索?
采纳答案by Bart van den Berg
Thanks guys for the feedback. Found a solution in completely recreating the UINavigationController's behavior. When I was nearly finished I ran into Nick Lockwood's solution:
谢谢大家的反馈。找到了完全重新创建 UINavigationController 行为的解决方案。当我快完成时,我遇到了 Nick Lockwood 的解决方案:
https://github.com/nicklockwood/OSNavigationController
https://github.com/nicklockwood/OSNavigationController
OSNavigationController is a open source re-implementation of UINavigationController. It currently features only a subset of the functionality of UINavigationController, but the long-term aim is to replicate 100% of the features.
OSNavigationController 是 UINavigationController 的开源重新实现。它目前仅具有 UINavigationController 功能的一个子集,但长期目标是复制 100% 的功能。
OSNavigationController is not really intended to be used as-is. The idea is that you can fork it and then easily customize its appearance and behaviour to suit any special requirements that your app may have. Customizing OSNavigationController is much simpler than trying to customize UINavigationController due to the fact that the code is open and you don't need to worry about private methods, undocumented behavior, or implementation changes between versions.
OSNavigationController 并不是真的打算按原样使用。这个想法是,您可以分叉它,然后轻松自定义其外观和行为,以满足您的应用程序可能具有的任何特殊要求。自定义 OSNavigationController 比尝试自定义 UINavigationController 简单得多,因为代码是开放的,您无需担心私有方法、未记录的行为或版本之间的实现更改。
By overriding my UINavigationController with his code, I was able to work with background images in UINavigationcontrollers
通过用他的代码覆盖我的 UINavigationController,我能够在 UINavigationControllers 中处理背景图像
Thanks!
谢谢!
回答by Arne
I managed to workaround the new transition type by creating a category for UINavigationController. In my case I needed to revert it to the old transition style because I have transparent viewControllers that slide over a static background.
我设法通过为UINavigationController. 在我的情况下,我需要将它恢复到旧的过渡样式,因为我有透明的 viewControllers 可以在静态背景上滑动。
UINavigationController+Retro.h
@interface UINavigationController (Retro) - (void)pushViewControllerRetro:(UIViewController *)viewController; - (void)popViewControllerRetro; @endUINavigationController+Retro.m
#import "UINavigationController+Retro.h" @implementation UINavigationController (Retro) - (void)pushViewControllerRetro:(UIViewController *)viewController { CATransition *transition = [CATransition animation]; transition.duration = 0.25; transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; transition.type = kCATransitionPush; transition.subtype = kCATransitionFromRight; [self.view.layer addAnimation:transition forKey:nil]; [self pushViewController:viewController animated:NO]; } - (void)popViewControllerRetro { CATransition *transition = [CATransition animation]; transition.duration = 0.25; transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; transition.type = kCATransitionPush; transition.subtype = kCATransitionFromLeft; [self.view.layer addAnimation:transition forKey:nil]; [self popViewControllerAnimated:NO]; } @end
UINavigationController+Retro.h
@interface UINavigationController (Retro) - (void)pushViewControllerRetro:(UIViewController *)viewController; - (void)popViewControllerRetro; @endUINavigationController+Retro.m
#import "UINavigationController+Retro.h" @implementation UINavigationController (Retro) - (void)pushViewControllerRetro:(UIViewController *)viewController { CATransition *transition = [CATransition animation]; transition.duration = 0.25; transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; transition.type = kCATransitionPush; transition.subtype = kCATransitionFromRight; [self.view.layer addAnimation:transition forKey:nil]; [self pushViewController:viewController animated:NO]; } - (void)popViewControllerRetro { CATransition *transition = [CATransition animation]; transition.duration = 0.25; transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; transition.type = kCATransitionPush; transition.subtype = kCATransitionFromLeft; [self.view.layer addAnimation:transition forKey:nil]; [self popViewControllerAnimated:NO]; } @end
回答by ArtFeel
I have the same problem with clear background colors and crappy animations, so I create custom transitioning for ViewController with new iOS7 API. All you need is simply set a delegate for your navigation controller:
我在清晰的背景颜色和蹩脚的动画方面遇到了同样的问题,所以我使用新的 iOS7 API 为 ViewController 创建了自定义过渡。您所需要的只是为您的导航控制器设置一个委托:
// NavigationController does not retain delegate, so you should hold it.
self.navigationController.delegate = self.navigationTransitioningDelegate;
Just add this files into your project: MGNavigationTransitioningDelegate.
只需将此文件添加到您的项目中:MGNavigationTransitioningDelegate。
回答by Joel
I had a problem where when UIViewController A did a pushViewController to push UIViewController B, the push animation would stop at about 25%, halt, and then slide B in the rest of the way.
我遇到了一个问题,当 UIViewController A 执行 pushViewController 来推送 UIViewController B 时,推送动画会在大约 25% 处停止,暂停,然后在剩下的过程中滑动 B。
This DID NOT happen on iOS 6, but as soon as I started using iOS 7 as the base SDK in XCode 5, this started happening.
这在 iOS 6 上没有发生,但是当我开始使用 iOS 7 作为 XCode 5 中的基本 SDK 时,这开始发生。
The fix is that view controller B did not have a backgroundColor set on its root view (the root view is the one that is the value of viewController.view, that you typically set in loadView). Setting a backgroundColor in that root view's initializer fixed the problem.
修复是视图控制器 B 没有在其根视图上设置 backgroundColor(根视图是 viewController.view 的值,通常在 loadView 中设置)。在该根视图的初始值设定项中设置 backgroundColor 解决了该问题。
I managed to fix this as follows:
我设法解决这个问题如下:
// CASE 1: The root view for a UIViewController subclass that had a halting animation
- (id)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame])) {
// Do some initialization ...
// self.backgroundColor was NOT being set
// and animation in pushViewController was slow and stopped at 25% and paused
}
return self;
}
// CASE 2: HERE IS THE FIX
- (id)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame])) {
// Do some initialization ...
// Set self.backgroundColor for the fix!
// and animation in pushViewController is no longer slow and and no longer stopped at 25% and paused
self.backgroundColor = [UIColor whiteColor]; // or some other non-clear color
}
return self;
}
回答by voratima
First of, I'm not using Storyboard. I tried using UINavigationController+Retro. For some reason, the UINavigationController is having a hard time releasing the UIViewController at the top of the stack. Here's the solution that works for me using iOS 7 custom transition.
首先,我没有使用故事板。我尝试使用 UINavigationController+Retro。出于某种原因, UINavigationController 很难释放堆栈顶部的 UIViewController 。这是使用 iOS 7 自定义转换对我有用的解决方案。
Set delegate to self.
navigationController.delegate = self;Declare this UINavigationControllerDelegate.
- (id<UIViewControllerAnimatedTransitioning>)navigationController (UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC { TransitionAnimator *animator = [TransitionAnimator new]; animator.presenting = YES; return animator; }Note that it'll only get called when animated is set to YES. For example
[navigationController pushViewController:currentViewController animated:YES];Create the animator class extending NSObject. I called mine TransitionAnimator, which was modified from TeehanLax's TLTransitionAnimator inside UIViewController-Transitions-Example.
TransitionAnimator.h
#import <Foundation/Foundation.h> @interface TransitionAnimator : NSObject <UIViewControllerAnimatedTransitioning> @property (nonatomic, assign, getter = isPresenting) BOOL presenting; @endTransitionAnimator.m
#import "TransitionAnimator.h" @implementation TransitionAnimator - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext { return 0.5f; } - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext{ UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; if (self.presenting) { //ANIMATE VC ENTERING FROM THE RIGHT SIDE OF THE SCREEN [transitionContext.containerView addSubview:fromVC.view]; [transitionContext.containerView addSubview:toVC.view]; toVC.view.frame = CGRectMake(0, 0, 2*APP_W0, APP_H0); //SET ORIGINAL POSITION toVC OFF TO THE RIGHT [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{ fromVC.view.frame = CGRectMake(0, (-1)*APP_W0, APP_W0, APP_H0); //MOVE fromVC OFF TO THE LEFT toVC.view.frame = CGRectMake(0, 0, APP_W0, APP_H0); //ANIMATE toVC IN TO OCCUPY THE SCREEN } completion:^(BOOL finished) { [transitionContext completeTransition:YES]; }]; }else{ //ANIMATE VC EXITING TO THE RIGHT SIDE OF THE SCREEN } } @endUse presenting flag to set the direction you want to animate or which ever condition you prefer. Here's the linkto Apple reference.
将委托设置为自己。
navigationController.delegate = self;声明这个 UINavigationControllerDelegate。
- (id<UIViewControllerAnimatedTransitioning>)navigationController (UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC { TransitionAnimator *animator = [TransitionAnimator new]; animator.presenting = YES; return animator; }请注意,只有当动画设置为 YES 时才会调用它。例如
[navigationController pushViewController:currentViewController animated:YES];创建扩展 NSObject 的动画师类。我调用了我的 TransitionAnimator,它是从UIViewController-Transitions-Example 中的TeehanLax 的 TLTransitionAnimator 修改而来的。
过渡动画.h
#import <Foundation/Foundation.h> @interface TransitionAnimator : NSObject <UIViewControllerAnimatedTransitioning> @property (nonatomic, assign, getter = isPresenting) BOOL presenting; @endTransitionAnimator.m
#import "TransitionAnimator.h" @implementation TransitionAnimator - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext { return 0.5f; } - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext{ UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; if (self.presenting) { //ANIMATE VC ENTERING FROM THE RIGHT SIDE OF THE SCREEN [transitionContext.containerView addSubview:fromVC.view]; [transitionContext.containerView addSubview:toVC.view]; toVC.view.frame = CGRectMake(0, 0, 2*APP_W0, APP_H0); //SET ORIGINAL POSITION toVC OFF TO THE RIGHT [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{ fromVC.view.frame = CGRectMake(0, (-1)*APP_W0, APP_W0, APP_H0); //MOVE fromVC OFF TO THE LEFT toVC.view.frame = CGRectMake(0, 0, APP_W0, APP_H0); //ANIMATE toVC IN TO OCCUPY THE SCREEN } completion:^(BOOL finished) { [transitionContext completeTransition:YES]; }]; }else{ //ANIMATE VC EXITING TO THE RIGHT SIDE OF THE SCREEN } } @end
回答by Riko87
Simply add in:
只需添加:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
This:
这个:
[[self window] setBackgroundColor:[UIColor whiteColor]];
The final result:
最终结果:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions (NSDictionary *)launchOptions {
[[self window] setBackgroundColor:[UIColor whiteColor]];
// Override point for customization after application launch.
return YES;
}
回答by John Jacecko
Apparently in iOS7 there's a new way define your own custom UIViewController transitions. Look in the docs for UIViewControllerTransitioningDelegate. Also, here's a link to an article about it: http://www.doubleencore.com/2013/09/ios-7-custom-transitions/
显然,在 iOS7 中有一种新方法可以定义您自己的自定义 UIViewController 转换。查看 UIViewControllerTransitioningDelegate 的文档。另外,这是一篇关于它的文章的链接:http: //www.doubleencore.com/2013/09/ios-7-custom-transitions/
回答by Bart van den Berg
Found another great resource to help out:
找到了另一个很好的资源来提供帮助:
http://www.teehanlax.com/blog/custom-uiviewcontroller-transitions
http://www.teehanlax.com/blog/custom-uiviewcontroller-transitions
Using iOS7 TLTransitionAnimator to create custom animations
使用 iOS7 TLTransitionAnimator 创建自定义动画
回答by uerceg
I voted for @Arne's answer, because I find it the most elegant solution to this problem. I would just like to add some code in order to answer to @Bill's problem from his comment on @Arne's solution. Here's comment quote:
我投票支持@Arne 的答案,因为我发现它是解决这个问题的最优雅的方法。我只想添加一些代码,以便从他对@Arne 解决方案的评论中回答@Bill 的问题。这是评论引用:
Thanks, this works for me. However, when the user taps the Back button, it reverts to the busted animation (because the back button doesn't call popViewControllerRetro). – Bill Oct 3 at 12:36
谢谢,这对我有用。然而,当用户点击后退按钮时,它会恢复到被破坏的动画(因为后退按钮不会调用 popViewControllerRetro)。– 比尔 10 月 3 日 12:36
In order to call popViewControllerRetro when back button is pressed, there's a small hack you can perform in order to achieve this. Go into your pushed view controller, import UIViewController+Retro.h and add this code in your viewWillDisappear method:
为了在按下后退按钮时调用 popViewControllerRetro,您可以执行一个小技巧来实现这一点。进入你的推送视图控制器,导入 UIViewController+Retro.h 并在你的 viewWillDisappear 方法中添加以下代码:
- (void)viewWillDisappear:(BOOL)animated {
if ([self.navigationController.viewControllers indexOfObject:self] == NSNotFound) {
[self.navigationController popViewControllerRetro];
}
[super viewWillDisappear:animated];
}
This if statement will detect when Back button is pressed and will call popViewControllerRetro from category class.
这个 if 语句将检测何时按下后退按钮,并将从类别类调用 popViewControllerRetro。
Best regards.
此致。

