【问题标题】:Transition of view controllers - from left to right视图控制器的过渡 - 从左到右
【发布时间】:2013-03-15 22:17:18
【问题描述】:

我没有使用导航控制器,而是使用故事板。

我必须从 1 个视图控制器过渡到另一个,为此我正在使用 segue。

现在我将 segue 样式设置为 Custom,并在相应的类中覆盖 perform 方法。

-(void)perform
{
    UIViewController *sourceViewController = [self sourceViewController];
    UIViewController *destinationViewController = [self destinationViewController];

    CATransition *transition = [CATransition animation];
    transition.duration = 0.25;
    transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
    transition.type = kCATransitionPush;
    transition.subtype = kCATransitionFromLeft;

    [sourceViewController.view.layer addAnimation:transition forKey:kCATransition];animated:NO];
    [sourceViewController presentViewController:destinationViewController animated:YES completion:nil];
}

但是还有一个目标视图控制器的属性modalTransitionStyle

所以现在,源 VC 从左到右就像被推送一样,但我想表明它是由目标视图控制器推送的。相反,目标 VC 默认执行“Cover Vertical”,modalTransitionStyle 属性只有四个选项可用,其中没有一个对我有用。

我认为要让它工作,这个动画应该被添加到一些超级视图层,一个超级视图,两个视图控制器都从中呈现。但是没有这样的superview..

【问题讨论】:

    标签: ios uiviewcontroller transition


    【解决方案1】:

    我的应用程序中的所有 ViewControllers 都继承自 MyViewController,除了一些其他默认行为之外,它还具有以下属性:

    @property(readwrite, nonatomic) BOOL slideFromSide;
    

    还有这段代码:

    - (void) presentViewController: (UIViewController*) vc animated: (BOOL) flag completion: (void (^)(void)) completion
    {
        BOOL slideIn = NO;
        if ([vc isKindOfClass: [MyViewController class]])
        {
            MyViewController *svc = (MyViewController*) vc;
            slideIn = svc.slideFromSide;
        }
    
        if (slideIn)
        {
            [self addChildViewController: vc];
            [self.view addSubview: vc.view];
    
            CGRect frame = vc.view.frame;
            frame.origin.x = frame.size.width;
            vc.view.frame = frame;
    
            frame.origin.x = 0;
            [UIView animateWithDuration: 0.33
                             animations: ^{
                                 vc.view.frame = frame;
                             }
             ];
        }
        else
        {
            [super presentViewController: vc animated: flag completion: completion];
        }
    }
    
    
    - (IBAction) backAction: (id) sender
    {
        if (_slideFromSide)
        {
            CGRect frame = self.view.frame;
            frame.origin.x = frame.size.width;
            [UIView animateWithDuration: 0.33
                             animations: ^{
                                 self.view.frame = frame;
                             }
                             completion:^(BOOL finished) {
                                 [self removeFromParentViewController];
                             }
             ];
        }
        else
        {
            [self dismissViewControllerAnimated: YES completion: nil];
        }
    }
    

    然后,在我想要滑入的 ViewControllers 中,我有:

    - (id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
    {
        self = [super initWithNibName: nibNameOrNil bundle: nibBundleOrNil];
        if (self)
        {
            self.slideFromSide = YES;
            // Whatever else you want to do
        }
    
        return self;
    }
    

    调用一个新的 ViewController 就像平常一样:

    WhateverViewController *vc = [WhateverViewController alloc] initWithNibName: nil bundle: nil];
    [self presentViewController: vc animated: YES completion: nil];
    

    【讨论】:

      【解决方案2】:

      通常你会给destinationController一个storyboardId,然后从sourceViewController这样调用它:

      //push next view
      UIStoryboard *storyboard = self.storyboard;
      YourViewControllerClass *destVC = [storyboard instantiateViewControllerWithIdentifier:@"StoryboardID"];
      [self.navigationController pushViewController:destVC animated:YES];
      

      您也可以像这样手动操作:

          // Get the views.
          UIView * fromView = sourceViewController.view;
          UIView * toView = destinationViewController.view;
      
          // Get the size of the view area.
          CGRect viewSize = fromView.frame;
      
          // Add the toView to the fromView
          [fromView.superview addSubview:toView];
      
          // Position it off screen.
          toView.frame = CGRectMake( 320 , viewSize.origin.y, 320, viewSize.size.height);
      
          [UIView animateWithDuration:0.4 animations:
           ^{
               // Animate the views on and off the screen. This will appear to slide.
               fromView.frame =CGRectMake( -320 , viewSize.origin.y, 320, viewSize.size.height);
               toView.frame =CGRectMake(0, viewSize.origin.y, 320, viewSize.size.height);
           }
                           completion:^(BOOL finished)
           {
               if (finished)
               {
                   // Remove the old view from its parent.
                   [fromView removeFromSuperview];
      
                   //I use it to have navigationnBar and TabBar at the same time
                   //self.tabBarController.selectedIndex = indexPath.row+1;
               }
           }];
      

      ** 编辑 **

      反函数(类似于导航控制器中的后退按钮):

      // Get the views.
      UIView * fromView = fromViewController.view;
      UIView * toView = destViewController.view;
      
      // Get the size of the view area.
      CGRect viewSize = fromView.frame;
      
      // Add the to view to the tab bar view.
      [fromView.superview addSubview:toView];
      
      // Position it off screen.
      toView.frame = CGRectMake( -320 , viewSize.origin.y, 320, viewSize.size.height);
      
      [UIView animateWithDuration:0.4 animations:
       ^{
           // Animate the views on and off the screen. This will appear to slide.
           fromView.frame =CGRectMake( 320 , viewSize.origin.y, 320, viewSize.size.height);
           toView.frame =CGRectMake(0, viewSize.origin.y, 320, viewSize.size.height);
       }
                       completion:^(BOOL finished)
       {
           if (finished)
           {
               // Remove the old view from the tabbar view.
               [fromView removeFromSuperview];
           }
       }];
      

      【讨论】:

      • 我没有使用导航控制器。您的第二种方法是否与“呈现”视图相同?我的意思是它会调用viewWillAppear 和其他此类方法吗?我是否能够“关闭”视图,或者我会做类似的事情来删除视图?
      • 或者你能告诉我一些步骤,我可以将我的应用程序转换为使用导航控制器吗?我有 VC1,它可以呈现 VC2 或 VC3。 VC2 和 VC3 必须相互关联。
      • @neeraj 第二种方法将在右侧附加第二个视图,向右滑动直到只有该视图可见,然后关闭第一个视图。所有相应的方法,例如viewDidLoadviewWillAppear 将照常调用。如果您所说的关闭是指类似于dismissModalViewControllerAnimated: 生成的行为,您可以通过调用一个功能相同但顺序相反的函数来实现(将新视图附加到左侧并滑动到左侧)。
      • @neeraj 我在答案中添加了一个编辑以模拟向后滑动
      • 非常感谢 simpleBob。但我认为这可能需要对应用程序进行一些重大更改!
      猜你喜欢
      • 1970-01-01
      • 2012-07-28
      • 2018-10-29
      • 1970-01-01
      • 2016-10-26
      • 1970-01-01
      • 2017-12-01
      • 2019-05-26
      • 2019-01-11
      相关资源
      最近更新 更多