ios 在不使用导航控制器堆栈、子视图或模态控制器的情况下动画更改视图控制器?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8146253/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Animate change of view controllers without using navigation controller stack, subviews or modal controllers?
提问by TigerCoding
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?
有人可以在没有上述限制的情况下更改视图控制器并允许在它们之间进行动画转换吗?
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 应该是这个问题的基本操作系统,我应该在提到故事板(上面)时澄清这一点。
采纳答案by XJones
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 (e.g. window.rootViewController.view.anotherView
).
编辑:适用于任何方向的新答案。原始答案仅在界面处于纵向时才有效。这是 b/c 视图转换动画,它替换带有不同视图的视图,并且视图必须至少低于添加到窗口的第一个视图(例如window.rootViewController.view.anotherView
)。
I've implemented a simple container class I called TransitionController
. You can find it at https://gist.github.com/1394947.
我已经实现了一个简单的容器类,我称之为TransitionController
. 您可以在https://gist.github.com/1394947找到它。
As an aside, I prefer the implementation in a separate class b/c it's easier to reuse. 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. The logic you'd need would be the same however.
顺便说一句,我更喜欢在单独的类 b/c 中实现它更容易重用。如果您不希望那样,您可以简单地直接在您的应用程序委托中实现相同的逻辑,从而消除对TransitionController
类的需要。但是,您需要的逻辑是相同的。
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:
我对这个例子做了以下假设:
You have a view controller assigned as the
rootViewController
of your windowWhen you switch to a new view you want to replace the current viewController with the viewController owning the new view. At any time, only the current viewController is alive (e.g. alloc'ed).
您有一个视图控制器分配为
rootViewController
您的窗口当您切换到新视图时,您希望将当前的 viewController 替换为拥有新视图的 viewController。在任何时候,只有当前的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
在应用程序委托中动画过渡的代码
- (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];
}
回答by timthetoolman
You can use Apple's new viewController containment system. For more in-depth information check out the WWDC 2011 session video "Implementing UIViewController
Containment".
您可以使用 Apple 的新 viewController 包含系统。如需更深入的信息,请查看 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. This is how the UISplitViewController works. 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. This is the Apple approved way of doing things and animating from one child viewController is painless. Plus you get to use all the various different UIViewAnimationOption
transitions!
iOS5 的新功能,UIViewController
Containment 允许您拥有一个父视图控制器和许多包含在其中的子视图控制器。这就是 UISplitViewController 的工作方式。这样做您可以在父级中堆叠视图控制器,但对于您的特定应用程序,您只是使用父级来管理从一个可见视图控制器到另一个的转换。这是 Apple 认可的做事方式,从一个子视图控制器制作动画是无痛的。另外,您可以使用所有各种不同的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. You can simply use the following to make sure your parentViewController forwards rotation events to the child viewControllers.
此外,使用 UIViewContainment,您不必担心(除非您愿意)在方向事件期间管理子视图控制器的混乱。您可以简单地使用以下内容来确保您的 parentViewController 将旋转事件转发到子 viewController。
- (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:
然后当您需要更改子视图控制器时,您可以在父视图控制器中调用以下内容:
-(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. This other projectshows how to use UIViewController
Containment on some various input viewController types that do not take up the whole screen.
Good luck
我在这里发布了一个完整的示例项目:https: //github.com/toolmanGitHub/stackedViewControllers。这个另一个项目展示了如何UIViewController
在一些不占据整个屏幕的输入 viewController 类型上使用Containment。祝你好运
回答by Richard Brightwell
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. Don't vote me down. :)
好的,我知道这个问题没有使用导航控制器,但没有理由不这样做。OP 没有及时回复评论让我睡觉。不要给我投票。:)
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];
回答by Ryan Artecona
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. 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.
正如这篇关于 custom segues 的帖子所述,制作自定义 segues 实际上真的很容易。它们在 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. I also only needed support for iOS 5+. Code:
就我而言,我希望发生类似的替换转场,但要进行FlipFromLeft
转换。我也只需要支持 iOS 5+。代码:
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à!
现在,按住 Control 并拖动以设置任何其他类型的转场,然后将其设为自定义转场,然后输入自定义转场类的名称,等等!
回答by aopsfan
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. This is where we'll do all the dirty work--other classes will be able to "cleanly" call instance methods like pushViewController:
and such. In your .h
:
首先,创建一个新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;
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!
祝你好运,我希望这会有所帮助!
回答by Deepak Kumar Sahu
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.
此代码提供从视图控制器到另一个具有导航控制器的视图控制器的转换。