【问题标题】:Push ViewController from Right To Left with UINavigationController使用 UINavigationController 从右向左推送 ViewController
【发布时间】:2011-01-25 19:47:25
【问题描述】:

众所周知,UINavigationController 从左到右推送 ViewController,有没有办法从右到左推送 View?就像后退按钮的动画一样。
现在我有这个:


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

【问题讨论】:

    标签: iphone objective-c uinavigationcontroller


    【解决方案1】:

    您可以从 navigationController 的 viewcontrollers 数组创建一个 NSMutableArray 并在当前视图控制器之前插入新的 viewController。然后设置没有动画的 viewControllers 数组并弹回来。

    UIViewController *newVC = ...;
    NSMutableArray *vcs =  [NSMutableArray arrayWithArray:self.navigationController.viewControllers];
    [vcs insertObject:newVC atIndex:[vcs count]-1];
    [self.navigationController setViewControllers:vcs animated:NO];
    [self.navigationController popViewControllerAnimated:YES];
    

    【讨论】:

    • 有趣的方法。可以工作,但可能会带来一些令人头疼的问题。
    • 听起来很有趣。我需要在 ViewController 中传递一些信息,所以也许它可以通过这种方式工作。你能告诉我如何在当前 ViewController 之前插入我的新 ViewController 吗?
    • 我添加了一个代码 sn-p,说明了这种方法。这绝对不符合 HIG,并且可能会使用户感到困惑。但它应该做你所要求的。不过我没有测试。
    • 我基于这个想法创建了 UINavigationController 的工作子类:bit.ly/iOS-rtl
    • 太老套了。使用 CATransition 应该是正确的方法。
    【解决方案2】:

    请试试这个

    HomePageController  *pageView = [[HomePageController alloc] initWithNibName:@"HomePageController_iPhone" bundle:nil];
    
    CATransition *transition = [CATransition animation];
    transition.duration = 0.45;
    transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];
    transition.type = kCATransitionPush;
    transition.subtype = kCATransitionFromLeft;
    transition.delegate = self;
    [self.navigationController.view.layer addAnimation:transition forKey:nil];
    
    self.navigationController.navigationBarHidden = NO;
    [self.navigationController pushViewController:pageView animated:NO];
    

    【讨论】:

    • 为什么要设置两次转场的类型?
    • 类型应该是 kCATransitionPush 和子类型 kCATransitionFromLeft。设置类型两次是多余的。我会编辑答案
    【解决方案3】:
    Try this :  
    //Push effect in reverse way
        CATransition* transition = [CATransition animation];
        transition.duration = 0.75;
        transition.type = kCATransitionPush;
        transition.subtype = kCATransitionFromLeft;
        [self.navigationController.view.layer addAnimation:transition forKey:kCATransition];
        [self.navigationController pushViewController:vc animated:NO];
    

    【讨论】:

      【解决方案4】:

      此代码运行良好。请尝试

      CATransition *transition = [CATransition animation];
      transition.duration = 0.3f;
      transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
      transition.type = kCATransitionReveal;
      [self.navigationController.view.layer addAnimation:transition forKey:nil];
      [self.navigationController pushViewController:phoneServicesViewController animated:NO];
      

      【讨论】:

      • 终于!我已经尝试了几个小时,但直到你的工作都没有成功。
      • @TriannaBrannon 很高兴听到代码 sn-ps 对您有帮助。
      【解决方案5】:

      你似乎想“弹回来”。这可以通过UINavigationController 实例上的三种方法来实现:

      回到“根”控制器:

      -(NSArray *)popToRootViewControllerAnimated:(BOOL)animated

      或者回到以前的控制器之一:

      -(NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated

      或者回到之前推送的控制器:

      -(UIViewController *)popViewControllerAnimated:(BOOL)animated

      【讨论】:

      • 感谢您的帮助,我只是想试试 Felix 的答案,但不知道该怎么做
      【解决方案6】:

      不,从右到左保留用于从导航堆栈中弹出视图控制器。但是,您可以通过自己为视图设置动画来获得这样的效果。比如:

      [UIView beginAnimations:@"rightToLeft" context:NULL];
      CGRect newFrame = aView.frame;
      newFrame.origin.x -= newFrame.size.width;
      aView.frame = newFrame;
      [UIView commitAnimations];
      

      但这不会对您的导航控制器做任何事情。

      【讨论】:

      • 很高兴知道,如果我从导航堆栈中弹出视图怎么办?
      • @Ludo:您不能从导航堆栈中弹出视图。 “堆栈”包含视图控制器
      • 对不起,我的错。我输入了视图,但当然想到了视图控制器。其他答案解释了如何弹出视图控制器。
      【解决方案7】:

      在我看来,这只是对最佳答案的改进:

      UIViewController *newVC = ...;
      [self.navigationController setViewControllers:@[newVC, self] animated:NO];
      [self.navigationController popViewControllerAnimated:YES];
      

      要返回初始控制器,只需对其进行推送即可。

      【讨论】:

        【解决方案8】:

        根据@felixlam 的回答,我升级并创建了一个“反向”方向导航控制器,它会覆盖默认的 push/pop 方法以像这样操作。

        class LeftPushNavigationController: BaseNavigationController {
        
          override func viewDidLoad() {
            super.viewDidLoad()
            interactivePopGestureRecognizer?.isEnabled = false
          }
        
          override func pushViewController(_ viewController: UIViewController, animated: Bool) {
            // If the push is not animated, simply pass to parent
            guard animated else { return super.pushViewController(viewController, animated: animated) }
        
            // Setup back button
            do {
              // Hide original back button
              viewController.navigationItem.setHidesBackButton(true, animated: false)
              // Add new one
              viewController.navigationItem.rightBarButtonItem = UIBarButtonItem(
                image: #imageLiteral(resourceName: "iconBackReverse"),
                style: .plain,
                target: self,
                action: #selector(self.pop)
              )
            }
        
            // Calculate final order
            let finalVCs = self.viewControllers + [viewController]
        
            // Insert the viewController to the before-last position (so it can be popped to)
            var viewControllers = self.viewControllers
            viewControllers.insert(viewController, at: viewControllers.count - 1)
        
            // Insert viewcontroller before the last one without animation
            super.setViewControllers(viewControllers, animated: false)
            // Pop with the animation
            super.popViewController(animated: animated)
            // Set the right order without animation
            super.setViewControllers(finalVCs, animated: false)
          }
        
          override func popViewController(animated: Bool) -> UIViewController? {
            // If the push is not animated, simply pass to parent
            guard animated else { return super.popViewController(animated: animated) }
        
            guard self.viewControllers.count > 1 else { return nil }
        
            // Calculate final order
            var finalVCs = self.viewControllers
            let viewController = finalVCs.removeLast()
        
            // Remove the parent ViewController (so it can be pushed)
            var viewControllers = self.viewControllers
            let parentVC = viewControllers.remove(at: viewControllers.count - 2)
        
            // Set the viewcontrollers without the parent & without animation
            super.setViewControllers(viewControllers, animated: false)
            // Create push animation with the parent
            super.pushViewController(parentVC, animated: animated)
            // Set the right final order without animation
            super.setViewControllers(finalVCs, animated: false)
        
            // Return removed viewController
            return viewController
          }
        
          @objc
          private func pop() {
            _ = popViewController(animated: true)
          }
        
        }
        

        【讨论】:

          【解决方案9】:

          Swift 5.0

           let pageView = TaskFolderListViewController.init(nibName: "HomePageController_iPhone", bundle: nil)
           let transition = CATransition()
           transition.duration = 0.45
           transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.default)
           transition.type = CATransitionType.push
           transition.subtype = CATransitionSubtype.fromLeft
           self.navigationController?.view.layer.add(transition, forKey: kCATransition)
           self.navigationController?.pushViewController(pageView, animated: false)
          

          【讨论】:

            【解决方案10】:

            我遇到了同样的问题,我就是这样解决的

            [self.navigationController popViewControllerAnimated:YES];
            

            这类似于“返回”,即单击返回按钮并导航到上一页的情况

            【讨论】:

              【解决方案11】:

              根据之前的最佳答案,您可以将UINavigationController 扩展并保留导航堆栈,如下所示:

              extension UINavigationController {
                  /// Pushes view controller into navigation stack with backwards animation.
                  func pushBackwards(viewController newViewController: UIViewController) {
                      if let currentController = viewControllers.last {
                          let previousControllers = viewControllers[0..<viewControllers.endIndex-1]
                          var controllers = Array(previousControllers + [newViewController, currentController])
                          setViewControllers(controllers, animated: false)
                          popViewController(animated: true)
                          // Adjusting the navigation stack
                          _ = controllers.popLast()
                          controllers.insert(currentController, at: controllers.count-1)
                          setViewControllers(controllers, animated: false)
                      } else {
                          // If there is no root view controller, set current one without animation.
                          setViewControllers([newViewController], animated: false)
                      }
                  }
              }
              
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2012-01-18
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2016-04-29
                • 2013-01-31
                • 1970-01-01
                相关资源
                最近更新 更多