简体   繁体   English

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

[英]Animate change of view controllers without using navigation controller stack, subviews or modal controllers?

NavigationControllers have ViewController stacks to manage, and limited animation transitions. NavigationControllers具有ViewController堆栈来管理和限制动画过渡。

Adding a view controller as a sub-view to an existing view controller requires passing events to the sub-view controller, which is a pain to manage, loaded with little annoyances and in general feels like a bad hack when implementing (Apple also recommends against doing this). 将视图控制器作为子视图添加到现有视图控制器需要将事件传递给子视图控制器,这很难管理,几乎没有烦恼,并且通常在实现时感觉像是一个糟糕的黑客(Apple也建议不要这样做)。

Presenting a modal view controller again places a view controller on top of another, and while it doesn't have the event passing problems described above, it doesn't really 'swap' the view controller, it stacks it. 呈现模式视图控制器再次将视图控制器放在另一个上面,虽然它没有上面描述的事件传递问题,但它并没有真正“交换”视图控制器,而是堆叠它。

Storyboards are limited to iOS 5, and are almost ideal, but cannot be used in all projects. 故事板仅限于iOS 5,几乎是理想的,但不能在所有项目中使用。

Can someone present a SOLID CODE EXAMPLE on a way to change view controllers without the above limitations and allows for animated transitions between them? 有人可以在没有上述限制的情况下更改视图控制器的方式提供一个SOLID代码示例,并允许它们之间的动画过渡?

A close example, but no animation: How to use multiple iOS custom view controllers without a navigation controller 一个接近的例子,但没有动画: 如何在没有导航控制器的情况下使用多个iOS自定义视图控制器

Edit: Nav Controller use is fine, but there needs to be animated transition styles (not simply the slide effects) the view controller being shown needs to be swapped completely (not stacked). 编辑:导航控制器使用很好,但需要动画过渡样式(不仅仅是幻灯片效果)显示的视图控制器需要完全交换(不是堆叠)。 If the second view controller must remove another view controller from the stack, then it's not encapsulated enough. 如果第二个视图控制器必须从堆栈中删除另一个视图控制器,那么它的封装不够。

Edit 2: iOS 4 should be the base OS for this question, I should have clarified that when mentioning storyboards (above). 编辑2:iOS 4应该是这个问题的基本操作系统,我应该在提到故事板时澄清(上图)。

EDIT: New answer that works in any orientation. 编辑:适用于任何方向的新答案。 The original answer only works when the interface is in portrait orientation. 原始答案仅在界面处于纵向时才有效。 This is b/c view transition animations that replace a view w/ a different view must occur with views at least a level below the first view added to the window (eg window.rootViewController.view.anotherView ). 这是b / c视图转换动画,用于替换具有不同视图的视图必须在视图至少低于添加到窗口的第一个视图的某个级别(例如window.rootViewController.view.anotherView )。

I've implemented a simple container class I called TransitionController . 我已经实现了一个名为TransitionController的简单容器类。 You can find it at https://gist.github.com/1394947 . 您可以在https://gist.github.com/1394947找到它。

As an aside, I prefer the implementation in a separate class b/c it's easier to reuse. 顺便说一句,我更喜欢在单独的类b / c中实现它更容易重用。 If you don't want that, you could simply implement the same logic directly in your app delegate eliminating the need for the TransitionController class. 如果您不想这样,您可以直接在您的app委托中实现相同的逻辑,从而无需TransitionController类。 The logic you'd need would be the same however. 然而,你需要的逻辑是相同的。

Use it as follows: 使用方法如下:

In your app delegate 在您的应用代表中

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

To transition to a new view controller from any view controller 从任何视图控制器转换到新视图控制器

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

EDIT: Original Answer below - only works for portait orientation 编辑:下面的原始答案 - 仅适用于肖像方向

I made the following assumptions for this example: 我为这个例子做了以下假设:

  1. You have a view controller assigned as the rootViewController of your window 您有一个视图控制器被指定为窗口的rootViewController

  2. When you switch to a new view you want to replace the current viewController with the viewController owning the new view. 当您切换到新视图时,您希望将当前viewController替换为拥有新视图的viewController。 At any time, only the current viewController is alive (eg alloc'ed). 在任何时候,只有当前的viewController是活的(例如,alloc'ed)。

The code can be easily modified to work differently, the key point is the animated transition and the single view controller. 代码可以很容易地修改为不同的工作,关键点是动画过渡和单视图控制器。 Make sure you don't retain a view controller anywhere outside of assigning it to window.rootViewController . 确保在将窗口分配给window.rootViewController之外的任何地方都不保留视图控制器。

Code to animate transition in app delegate 用于在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;
                    }];
}

Example use in a view controller 在视图控制器中使用的示例

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

You can use Apple's new viewController containment system. 您可以使用Apple的新viewController包含系统。 For more in-depth information check out the WWDC 2011 session video "Implementing UIViewController Containment". 有关更深入的信息,请查看WWDC 2011会话视频“实现UIViewController遏制”。

New to iOS5, UIViewController Containment allows you to have a parent viewController and a number of child viewControllers that are contained within it. iOS5新增功能, UIViewController Containment允许您拥有父视图控制器和包含在其中的多个子视图控制器。 This is how the UISplitViewController works. 这就是UISplitViewController的工作原理。 Doing this you can stack view controllers in a parent, but for your particular application you are just using the parent to manage the transition from one visible viewController to another. 这样做可以在父级中堆叠视图控制器,但对于您的特定应用程序,您只需使用父级来管理从一个可见的viewController到另一个的可见视图控制器的转换。 This is the Apple approved way of doing things and animating from one child viewController is painless. 这是Apple批准的做事方式和动画从一个孩子viewController是无痛的。 Plus you get to use all the various different UIViewAnimationOption transitions! 另外,您可以使用各种不同的UIViewAnimationOption过渡!

Also, with UIViewContainment, you do not have to worry, unless you want to, about the messiness of managing the child viewControllers during orientation events. 此外,使用UIViewContainment,除非您想要了解在定向事件期间管理子视图控制器的混乱,否则您不必担心。 You can simply use the following to make sure your parentViewController forwards rotation events to the child viewControllers. 您只需使用以下命令确保您的parentViewController将旋转事件转发给子viewControllers。

- (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers{
    return YES;
}

You can do the following or similar in your parent's viewDidLoad method to setup the first childViewController: 您可以在父视图的viewDidLoad方法中执行以下操作,以设置第一个childViewController:

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

then when you need to change the child viewController, you call something along the lines of the following within the parent viewController: 然后当你需要更改子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];
                             }];
 }

I posted a full example project here: https://github.com/toolmanGitHub/stackedViewControllers . 我在这里发布了一个完整的示例项目: https//github.com/toolmanGitHub/stackedViewControllers This other project shows how to use UIViewController Containment on some various input viewController types that do not take up the whole screen. 这个其他项目展示了如何在一些不占用整个屏幕的各种输入viewController类型上使用UIViewController Containment。 Good luck 祝好运

OK, I know the question says without using a navigation controller, but no reason not to. 好的,我知道这个问题没有使用导航控制器,但没有理由不这样做。 OP wasn't responding to comments in time for me to go to sleep. OP没有及时回应我的睡觉时间。 Don't vote me down. 不要投票给我。 :) :)

Here's how to pop the current view controller and flip to a new view controller using a navigation controller: 以下是使用导航控制器弹出当前视图控制器并翻转到新视图控制器的方法:

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

Since I just happened across this exact problem, and tried variations on all the pre-existing answers to limited success, I'll post how I eventually solved it: 由于我刚刚遇到了这个确切的问题,并尝试了所有预先存在的有限成功答案的变体,我将发布我最终如何解决它:

As described in this post on custom segues , it's actually really easy to make custom segues. 正如本文关于自定义segues的描述,实际上很容易制作自定义segues。 They are also super easy to hook up in Interface Builder, they keep relationships in IB visible, and they don't require much support by the segue's source/destination view controllers. 它们也非常容易在Interface Builder中连接,它们使IB中的关系可见,并且它们不需要segue的源/目标视图控制器的大量支持。

The post linked above provides iOS 4 code to replace the current top view controller on the navigationController stack with a new one using a slide-in-from-top animation. 上面链接的帖子提供了iOS 4代码,使用从上到下滑动的动画替换了navigationController堆栈上的当前顶视图控制器。

In my case, I wanted a similar replace segue to happen, but with a FlipFromLeft transition. 在我的情况下,我想要一个类似的替换segue发生,但有一个FlipFromLeft过渡。 I also only needed support for iOS 5+. 我也只需要支持iOS 5+。 Code: 码:

From RAFlipReplaceSegue.h: 来自RAFlipReplaceSegue.h:

#import <UIKit/UIKit.h>

@interface RAFlipReplaceSegue : UIStoryboardSegue
@end

From RAFlipReplaceSegue.m: 来自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

Now, control-drag to set up any other kind of segue, then make it a Custom segue, and type in the name of the custom segue class, et voilà! 现在,控制 - 拖动以设置任何其他类型的segue,然后将其设置为Custom segue,并输入自定义segue类的名称,etvoilà!

I struggled with this one for a long time, and one of my issues is listed here , I'm not sure if you have had that problem. 我很长一段时间都在努力解决这个问题,我的一个问题列在这里 ,我不确定你是否遇到过这个问题。 But here's what I would recommend if it must work with iOS 4. 但如果它必须适用于iOS 4,我会推荐这些。

Firstly, create a new NavigationController class. 首先,创建一个新的NavigationController类。 This is where we'll do all the dirty work--other classes will be able to "cleanly" call instance methods like pushViewController: and such. 这是我们将完成所有脏工作的地方 - 其他类将能够“干净地”调用像pushViewController:这样的实例方法。 In your .h : 在你的.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;

The child view controllers array will serve as a store for all the view controllers in our stack. 子视图控制器数组将用作堆栈中所有视图控制器的存储。 We would automatically forward all rotation and resizing code from the NavigationController 's view to the currentController . 我们会自动将所有旋转和调整代码从NavigationController的视图转发到currentController

Now, in our implementation: 现在,在我们的实施中:

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

Now you can implement your own custom pushViewController: , popViewController and such, using these method calls. 现在,您可以使用这些方法调用实现自己的自定义pushViewController:popViewController等。

Good luck, and I hope this helps! 祝你好运,我希望这有帮助!

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

Try This Code. 试试此代码。


This code gives Transition from a view controller to another view controller which having a navigation controller. 此代码提供从视图控制器到另一个具有导航控制器的视图控制器的转换。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 动态化视图控制器从一个到另一个的过渡,而无需导航控制器堆栈 - Animate transition of view controllers from one to another without navigation controller stack 在没有导航控制器的情 - Switching view controllers without navigation controller 使用堆栈的导航控制器/视图控制器 - Navigation Controllers/View Controllers working with a stack 问题将多个视图控制器推送到导航控制器堆栈 - Problem pushing multiple view controllers onto navigation controller stack 如何使用多个iOS自定义视图控制器而不使用导航控制器 - How to use multiple iOS custom view controllers without a navigation controller 在所有视图控制器iOS中使用Navigation Controller的MVYSideMenu - MVYSideMenu using Navigation Controller in all view controllers iOS 在视图控制器中添加多个导航控制器? - Adding multiple navigation controllers inside a view controller? 导航控制器未推入/弹出视图控制器 - Navigation Controller not Pushing/Popping View Controllers iPhone是否释放模态视图控制器也会将推送的控制器弹出堆栈? - iPhone Does releasing modal view controller also pop pushed controllers onto stack? 消除模态视图控制器 - Dismissing Modal View Controllers
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM