在不使用导航控制器堆栈,子视图或模态控制器的情况下更改视图控制器的动画?

Tig*_*ing 141 iphone uiviewcontroller uianimation ipad ios

NavigationControllers具有ViewController堆栈来管理和限制动画过渡.

将视图控制器作为子视图添加到现有视图控制器需要将事件传递给子视图控制器,这很难管理,几乎没有烦恼,并且通常在实现时感觉像是一个糟糕的黑客(Apple也建议不要这样做).

呈现模式视图控制器再次将视图控制器放在另一个上面,虽然它没有上面描述的事件传递问题,但它并没有真正"交换"视图控制器,而是堆叠它.

故事板仅限于iOS 5,几乎是理想的,但不能在所有项目中使用.

有人可以在没有上述限制的情况下更改视图控制器的方式提供一个SOLID代码示例,并允许它们之间的动画过渡?

一个接近的例子,但没有动画: 如何在没有导航控制器的情况下使用多个iOS自定义视图控制器

编辑:导航控制器使用很好,但需要动画过渡样式(不仅仅是幻灯片效果),显示的视图控制器需要完全交换(不是堆叠).如果第二个视图控制器必须从堆栈中删除另一个视图控制器,那么它的封装不够.

编辑2:iOS 4应该是这个问题的基本操作系统,我应该在提到故事板时澄清(上图).

XJo*_*nes 108

编辑:适用于任何方向的新答案. 原始答案仅在界面处于纵向时才有效.这是b/c视图转换动画,其替换具有不同视图的视图必须与视图至少比添加到窗口的第一视图低一级(例如window.rootViewController.view.anotherView).

我已经实现了一个我调用的简单容器类TransitionController.您可以在https://gist.github.com/1394947找到它.

顺便说一句,我更喜欢在单独的类b/c中实现它更容易重用.如果您不希望这样,您可以直接在您的app委托中实现相同的逻辑,从而无需使用TransitionController该类.然而,你需要的逻辑是相同的.

使用方法如下:

在您的应用代表中

// add a property for the TransitionController

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    MyViewController *vc = [[MyViewContoller alloc] init...];
    self.transitionController = [[TransitionController alloc] initWithViewController:vc];
    self.window.rootViewController = self.transitionController;
    [self.window makeKeyAndVisible];
    return YES;
}
Run Code Online (Sandbox Code Playgroud)

从任何视图控制器转换到新视图控制器

- (IBAction)flipToView
{
    anotherViewController *vc = [[AnotherViewController alloc] init...];
    MyAppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
    [appDelegate.transitionController transitionToViewController:vc withOptions:UIViewAnimationOptionTransitionFlipFromRight];
}
Run Code Online (Sandbox Code Playgroud)

编辑:下面的原始答案 - 仅适用于肖像方向

我为这个例子做了以下假设:

  1. 您有一个视图控制器被指定为rootViewController您的窗口

  2. 当您切换到新视图时,您希望将当前viewController替换为拥有新视图的viewController.在任何时候,只有当前的viewController是活的(例如,alloc'ed).

代码可以很容易地修改为不同的工作,关键点是动画过渡和单视图控制器.确保在分配视图控制器之外的任何地方都不保留视图控制器window.rootViewController.

用于在app委托中设置转换动画的代码

- (void)transitionToViewController:(UIViewController *)viewController
                    withTransition:(UIViewAnimationOptions)transition
{
    [UIView transitionFromView:self.window.rootViewController.view
                        toView:viewController.view
                      duration:0.65f
                       options:transition
                    completion:^(BOOL finished){
                        self.window.rootViewController = viewController;
                    }];
}
Run Code Online (Sandbox Code Playgroud)

在视图控制器中使用的示例

- (IBAction)flipToNextView
{
    AnotherViewController *anotherVC = [[AnotherVC alloc] init...];
    MyAppDelegate *appDelegate = (MyAppDelegate *)[UIApplication sharedApplication].delegate;
    [appDelegate transitionToViewController:anotherVC
                             withTransition:UIViewAnimationOptionTransitionFlipFromRight];
}
Run Code Online (Sandbox Code Playgroud)


tim*_*man 67

您可以使用Apple的新viewController包含系统.有关更深入的信息,请查看WWDC 2011会话视频"实施UIViewController遏制".

作为iOS5的新功能,UIViewControllerContainment允许您拥有父视图控制器和包含在其中的许多子视图控制器.这就是UISplitViewController的工作原理.这样做可以在父级中堆叠视图控制器,但对于您的特定应用程序,您只需使用父级来管理从一个可见的viewController到另一个的可见视图控制器的转换.这是Apple批准的做事方式和动画从一个孩子viewController是无痛的.另外,您可以使用各种不同的UIViewAnimationOption过渡!

此外,使用UIViewContainment,除非您想要了解在定向事件期间管理子视图控制器的混乱,否则您不必担心.您只需使用以下命令确保您的parentViewController将旋转事件转发给子viewControllers.

- (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers{
    return YES;
}
Run Code Online (Sandbox Code Playgroud)

您可以在父视图的viewDidLoad方法中执行以下操作,以设置第一个childViewController:

[self addChildViewController:self.currentViewController];
[self.view addSubview:self.currentViewController.view];
[self.currentViewController didMoveToParentViewController:self];
[self.currentViewController.swapViewControllerButton setTitle:@"Swap" forState:UIControlStateNormal];
Run Code Online (Sandbox Code Playgroud)

然后当你需要更改子viewController时,你在父viewController中调用下面的内容:

-(void)swapViewControllers:(childViewController *)addChildViewController:aNewViewController{
     [self addChildViewController:aNewViewController];
     __weak __block ViewController *weakSelf=self;
     [self transitionFromViewController:self.currentViewController
                       toViewController:aNewViewController
                               duration:1.0
                                options:UIViewAnimationOptionTransitionCurlUp
                             animations:nil
                             completion:^(BOOL finished) {
                                   [aNewViewController didMoveToParentViewController:weakSelf];

                                   [weakSelf.currentViewController willMoveToParentViewController:nil];
                                   [weakSelf.currentViewController removeFromParentViewController];

                                   weakSelf.currentViewController=[aNewViewController autorelease];
                             }];
 }
Run Code Online (Sandbox Code Playgroud)

我在这里发布了一个完整的示例项目:https: //github.com/toolmanGitHub/stackedViewControllers.这个其他项目展示了如何UIViewController在一些不占用整个屏幕的各种输入viewController类型上使用Containment.祝好运

  • 在WWDC的演示中,我似乎记得他们在调用开始转换之前调用它,因为转换并不意味着currentVC将移动到nil.对于UITabBarController,转换不会更改任何vc的父级.从父级删除调用didMoveToParentViewController:nil,但没有将...调用.恕我直言 (2认同)

Ric*_*ell 7

好的,我知道这个问题没有使用导航控制器,但没有理由不这样做.OP没有及时回应我的睡觉时间.不要投票给我.:)

以下是使用导航控制器弹出当前视图控制器并翻转到新视图控制器的方法:

UINavigationController *myNavigationController = self.navigationController;
[[self retain] autorelease];

[myNavigationController popViewControllerAnimated:NO];

PreferencesViewController *controller = [[PreferencesViewController alloc] initWithNibName:nil bundle:nil];

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration: 0.65];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:myNavigationController.view cache:YES];
[myNavigationController pushViewController:controller animated:NO];
[UIView commitAnimations];

[controller release];
Run Code Online (Sandbox Code Playgroud)