38

所以。刚开始将我的 IOS 代码转换到 IOS7,并遇到了一些问题。

我有一个UINavigationController,它有子 ViewControllers ,我pushViewController用来显示下一个视图。要使用一组图像创建视差动画,如果自定义UINavigationController动画一组,UIImageViews我的子 ViewControllers 都具有self.backgroundColor = [UIColor clearColor]透明度。

自 iOS7 以来UINavController,通过部分移动当前视图控制器并在顶部推动新的视图控制器,更新了子 vc 的动画方式,我的视差动画看起来很糟糕。我看到之前的 VC 移动了一下,然后消失了。有什么办法可以恢复以前的UINavigationControllerpushViewController 动画吗?我似乎无法在代码中找到它。

WelcomeLoginViewController* welcomeLoginViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"WelcomeLogin"];
    [self.navigationController pushViewController:welcomeLoginViewController animated:YES];    

甚至尝试使用:

    [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];
                     }];

有没有人有任何线索?

4

10 回答 10

46

我设法通过为UINavigationController. 在我的情况下,我需要将其恢复为旧的过渡样式,因为我有透明的 viewControllers 可以在静态背景上滑动。

  • UINavigationController+Retro.h

    @interface UINavigationController (Retro)
    
    - (void)pushViewControllerRetro:(UIViewController *)viewController;
    - (void)popViewControllerRetro;
    
    @end
    
  • UINavigationController+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
    
于 2013-09-18T20:58:24.860 回答
22

我对清晰的背景颜色和糟糕的动画也有同样的问题,所以我使用新的 iOS7 API 为 ViewController 创建了自定义转换。您所需要的只是为您的导航控制器设置一个委托:

// NavigationController does not retain delegate, so you should hold it.
self.navigationController.delegate = self.navigationTransitioningDelegate;

只需将此文件添加到您的项目中:MGNavigationTransitioningDelegate

于 2013-11-28T11:40:54.643 回答
18

我遇到了一个问题,当 UIViewController A 执行 pushViewController 来推送 UIViewController B 时,推送动画会在大约 25% 处停止,停止,然后在其余部分滑动 B。

这在 iOS 6 上没有发生,但是当我开始在 XCode 5 中使用 iOS 7 作为基础 SDK 时,这种情况就开始发生了。

解决方法是视图控制器 B 没有在其根视图上设置背景颜色(根视图是 viewController.view 的值,通常在 loadView 中设置)。在该根视图的初始化程序中设置一个 backgroundColor 解决了这个问题。

我设法解决了这个问题:

// 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;

}
于 2013-10-02T03:42:57.573 回答
7

首先,我没有使用 Storyboard。我尝试使用 UINavigationController+Retro。出于某种原因,UINavigationController 很难在堆栈顶部释放 UIViewController。这是使用 iOS 7 自定义过渡对我有用的解决方案。

  1. 将委托设置为自己。

    navigationController.delegate = self;
    
  2. 声明这个 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];
    
  3. 创建扩展 NSObject 的动画师类。我调用了我的 TransitionAnimator,它是从UIViewController-Transitions-Example中的 TeehanLax 的 TLTransitionAnimator 修改而来的。

    过渡动画师.h

    #import <Foundation/Foundation.h>
    @interface TransitionAnimator : NSObject <UIViewControllerAnimatedTransitioning>
    @property (nonatomic, assign, getter = isPresenting) BOOL presenting;
    @end
    

    过渡动画师.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
    

    使用呈现标志来设置您想要动画的方向或您喜欢的任何条件。这是Apple参考的链接。

于 2013-10-08T04:56:52.697 回答
2

谢谢大家的反馈。找到了完全重新创建 UINavigationController 行为的解决方案。当我快要完成时,我遇到了尼克洛克伍德的解决方案:

https://github.com/nicklockwood/OSNavigationController

OSNavigationController 是 UINavigationController 的开源重新实现。它目前仅具有 UINavigationController 功能的子集,但长期目标是复制 100% 的功能。

OSNavigationController 并不是真的要按原样使用。这个想法是您可以分叉它,然后轻松自定义其外观和行为,以满足您的应用程序可能具有的任何特殊要求。自定义 OSNavigationController 比尝试自定义 UINavigationController 简单得多,因为代码是开放的,您无需担心私有方法、未记录的行为或版本之间的实现更改。

通过用他的代码覆盖我的 UINavigationController,我能够在 UINavigationcontrollers 中使用背景图像

谢谢!

于 2013-09-24T14:15:51.347 回答
2

只需添加:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

这:

[[self window] setBackgroundColor:[UIColor whiteColor]];

最终结果:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions (NSDictionary *)launchOptions {    
    [[self window] setBackgroundColor:[UIColor whiteColor]];

    // Override point for customization after application launch.
    return YES;
}
于 2014-07-03T09:19:56.920 回答
1

显然,在 iOS7 中有一种新方法可以定义您自己的自定义 UIViewController 转换。在文档中查找 UIViewControllerTransitioningDelegate。另外,这里有一篇关于它的文章的链接:http: //www.doubleencore.com/2013/09/ios-7-custom-transitions/

于 2013-09-24T16:50:03.260 回答
1

Arne 回答的 Swift 5 实现:

extension UINavigationController {
  func pushViewControllerLegacyTransition(_ viewController: UIViewController) {
    let transition = CATransition()
    transition.duration = 0.25
    transition.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
    transition.type = .push
    transition.subtype = .fromRight
    view.layer.add(transition, forKey: nil)
    pushViewController(viewController, animated: false)
  }

  func popViewControllerLegacyTransition() {
    let transition = CATransition()
    transition.duration = 0.25
    transition.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
    transition.type = .push
    transition.subtype = .fromLeft
    view.layer.add(transition, forKey: nil)
    popViewController(animated: false)
  }
}
于 2020-06-04T22:33:10.840 回答
0

找到了另一个很好的资源来提供帮助:

http://www.teehanlax.com/blog/custom-uiviewcontroller-transitions

使用 iOS7 TLTransitionAnimator 创建自定义动画

于 2013-09-27T10:27:30.310 回答
0

我投票支持@Arne 的答案,因为我发现它是解决这个问题的最优雅的解决方案。我只想添加一些代码,以便从他对@Arne 解决方案的评论中回答@Bill 的问题。以下是评论引述:

谢谢,这对我有用。但是,当用户点击后退按钮时,它会恢复为被破坏的动画(因为后退按钮不会调用 popViewControllerRetro)。– 比尔 10 月 3 日 12:36

为了在按下后退按钮时调用 popViewControllerRetro,您可以执行一个小技巧来实现此目的。进入你的推送视图控制器,导入 UIViewController+Retro.h 并在你的 viewWillDisappear 方法中添加这个代码:

- (void)viewWillDisappear:(BOOL)animated {
    if ([self.navigationController.viewControllers indexOfObject:self] == NSNotFound) {
        [self.navigationController popViewControllerRetro];
    }

    [super viewWillDisappear:animated];
}

此 if 语句将检测何时按下后退按钮并从类别类调用 popViewControllerRetro。

最好的祝福。

于 2013-11-22T07:29:55.987 回答