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

NavigationControllers具有ViewController堆栈来pipe理和限制animation转换。

将视图控制器作为子视图添加到现有的视图控制器需要将事件传递给子视图控制器,这是一个痛苦的pipe理,加载了一点烦恼,一般感觉像一个坏的黑客时,实施(苹果还build议这样做)。

呈现一个模式视图控制器再次放置一个视图控制器在另一个之上,虽然它没有上述事件传递的问题,它不真正“交换”视图控制器,它堆叠它。

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

有人可以提出一个固体代码示例的方式来更改视图控制器没有上述限制,并允许他们之间的animation过渡?

一个closures的例子,但没有animation: 如何使用多个iOS自定义视图控制器没有导航控制器

编辑:导航控制器使用是好的,但需要有animation过渡样式(而不是简单的幻灯片效果)所显示的视图控制器需要完全交换(不堆积)。 如果第二个视图控制器必须从堆栈中移除另一个视图控制器,那么它的封装不够。

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

编辑:新的答案在任何方向工作。 原始答案仅在界面处于纵向方向时才起作用。 这是b / c视图转换animation,取代视图w /一个不同的视图必须发生与视图至less在第一个视图添加到窗口(例如window.rootViewController.view.anotherView )以下的级别。

我已经实现了一个简单的容器类,我称为TransitionController 。 你可以在https://gist.github.com/1394947find它。;

另外,我更喜欢在一个单独的类b / c中实现它更容易重用。 如果你不想这样做,你可以直接在你的应用程序委托中直接实现相同的逻辑,而不需要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; } 

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

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

编辑:下面的原始答案 – 只适用于portait方向

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

  1. 你有一个视图控制器分配为你的窗口的rootViewController

  2. 当你切换到一个新的视图,你想用viewControllerreplace当前的viewController拥有新的视图。 在任何时候,只有当前viewController是活着的(例如alloc'ed)。

代码可以很容易地修改,以不同的方式工作,关键点是animation过渡和单个视图控制器。 确保你没有保留一个视图控制器的任何地方分配给window.rootViewController

在应用程序委托中animation转换的代码

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

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

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

您可以使用Apple的新viewController包含系统。 有关更深入的信息,请查看WWDC 2011会话video“实现UIViewController控制”。

UIViewController Containment是iOS5的新成员,它允许你有一个父viewController和一些包含在其中的子viewController。 这是UISplitViewController的工作原理。 这样做,你可以堆栈父视图控制器,butq为你的特定应用程序,你只是使用父母来pipe理从一个可见的viewController到另一个过渡。 这是苹果公司批准的做法和从一个孩子viewControlleranimation的方式是无痛的。 另外你可以使用所有不同的UIViewAnimationOption转换!

另外,使用UIViewContainment,除非你想要,否则你不必担心在定向事件期间pipe理子ViewController的混乱。 您可以简单地使用以下来确保您的parentViewController将旋转事件转发给子ViewController。

 - (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers{ return YES; } 

您可以在您的父级的viewDidLoad方法中执行以下或类似的操作来设置第一个childViewController:

 [self addChildViewController:self.currentViewController]; [self.view addSubview:self.currentViewController.view]; [self.currentViewController didMoveToParentViewController:self]; [self.currentViewController.swapViewControllerButton setTitle:@"Swap" forState:UIControlStateNormal]; 

那么当你需要改变子视图控制器的时候,你可以在父视图控制器中调用以下内容:

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

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

好的,我知道这个问题说没有使用导航控制器,但没有理由不。 OP没有及时回应我的意见,让我去睡觉。 别投我一票 🙂

以下是如何popup当前的视图控制器,并使用导航控制器翻转到新的视图控制器:

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

由于我刚刚发现了这个问题,并尝试了所有已有的有限成功答案的变体,所以我会发布我是如何最终解决的:

正如在这篇关于自定义赛段的文章中所描述的那样 ,制作自定义赛段实际上非常简单。 它们也非常容易连接到Interface Builder,它们使得IB中的关系保持可见,并且不需要segue的源/目的地视图控制器的大量支持。

上面链接的post提供了iOS 4代码,使用顶级滑动animationreplace导航控制器堆栈上的当前顶部视图控制器。

在我的情况下,我想要一个类似的replace继续发生,但与FlipFromLeft过渡。 我也只需要支持iOS 5+。 码:

来自RAFlipReplaceSegue.h:

 #import <UIKit/UIKit.h> @interface RAFlipReplaceSegue : UIStoryboardSegue @end 

来自RAFlipReplaceSegue.m:

 #import "RAFlipReplaceSegue.h" @implementation RAFlipReplaceSegue -(void) perform { UIViewController *destVC = self.destinationViewController; UIViewController *sourceVC = self.sourceViewController; [destVC viewWillAppear:YES]; destVC.view.frame = sourceVC.view.frame; [UIView transitionFromView:sourceVC.view toView:destVC.view duration:0.7 options:UIViewAnimationOptionTransitionFlipFromLeft completion:^(BOOL finished) { [destVC viewDidAppear:YES]; UINavigationController *nav = sourceVC.navigationController; [nav popViewControllerAnimated:NO]; [nav pushViewController:destVC animated:NO]; } ]; } @end 

现在,通过control-drag来设置任何其他types的segue,然后将其设置为一个Custom segue,并input自定义segue类的名称,等等!

我在这个问题上苦苦挣扎了很长一段时间,我的一个问题在这里列出,我不知道你是否有这个问题。 但是,如果它必须适用于iOS 4,我会推荐这么做。

首先,创build一个新的NavigationController类。 这就是我们要做所有肮脏工作的地方 – 其他类将能够“干净”地调用像pushViewController:这样的实例方法。 在你的.h

 @interface NavigationController : UIViewController { NSMutableArray *childViewControllers; UIViewController *currentViewController; } - (void)transitionFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController duration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL))completion; - (void)addChildViewController:(UIViewController *)childController; - (void)removeChildViewController:(UIViewController *)childController; 

子视图控制器数组将作为我们堆栈中所有视图控制器的存储。 我们会自动将所有旋转和resize的代码从NavigationController的视图到currentController

现在,在我们的实施中:

 - (void)transitionFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController duration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL))completion { currentViewController = [toViewController retain]; // Put any auto- and manual-resizing handling code here [UIView animateWithDuration:duration animations:animations completion:completion]; [fromViewController.view removeFromSuperview]; } - (void)addChildViewController:(UIViewController *)childController { [childViewControllers addObject:childController]; } - (void)removeChildViewController:(UIViewController *)childController { [childViewControllers removeObject:childController]; } 

现在你可以实现你自己定制的pushViewController:popViewController等等,使用这些方法调用。

祝你好运,我希望这有助于!

 UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; UINavigationController *viewController = (UINavigationController *)[storyboard instantiateViewControllerWithIdentifier:@"storyBoardIdentifier"]; viewController.modalTransitionStyle = UIModalTransitionStylePartialCurl; [self presentViewController:viewController animated:YES completion:nil]; 

试试这个代码。


这段代码给出了从视图控制器到具有导航控制器的另一个视图控制器的转换。