开发者

Stacked modal UIViewControllers don't animate as per doc?

In short, I have a root controller RootController presenting a modal navigation controller showing Controller1, which itself presents a modal navigation controller showing Controller2.

I want to dismiss Controller1 and Controller2 at the same time by sending the root controller a dismissModalViewControllerAnimated: message.

I expected to see an animation 开发者_StackOverflow社区of Controller2 being dismissed (or rather its navigation controller) and NOT see Controller1 in the process, taking me back to the root controller, as per the documentation:

If you present several modal view controllers in succession, and thus build a stack of modal view controllers, calling this method on a view controller lower in the stack dismisses its immediate child view controller and all view controllers above that child on the stack. When this happens, only the top-most view is dismissed in an animated fashion; any intermediate view controllers are simply removed from the stack. The top-most view is dismissed using its modal transition style, which may differ from the styles used by other view controllers lower in the stack.

However, Controller2 is being dismissed instantaneously without animation and I can see Controller1 being dismissed (with an animation). It might be a misunderstanding on my part of the documentation. If it is, could someone help me find a solution?

Here is a sample code that will demonstrate my problem (all superfluous code removed, no memory management, no error handling...):

// AppDelegate.h:
#import <UIKit/UIKit.h>
#import "RootController.h"

@interface AppDelegate : NSObject <UIApplicationDelegate> {
    IBOUTLET UIWindow *window;
    RootController *rootController;
}
@end


// AppDelegate.m:
#import "AppDelegate.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    rootController = [[RootController alloc] init];
    [window addSubview:rootController.view];
    [window makeKeyAndVisible];
    return YES;
}
@end



// RootController.h:
#import <UIKit/UIKit.h>
#import "Controller1.h"
@interface RootController : UIViewController {
    Controller1                 *controller1;
    UINavigationController      *controller1navigationController;
    UIButton                    *button;
}
@end


// RootController.m:
#import "RootController.h"
@implementation RootController
- (void)testMe:(id)target {
    controller1 = [[Controller1 alloc] init];
    controller1navigationController = [[UINavigationController alloc] initWithRootViewController:controller1];
    [self presentModalViewController:controller1navigationController animated:YES];
}
- (void)loadView {
    [super loadView];
    button = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain];
    [button setTitle:@"Test me" forState:UIControlStateNormal];
    button.frame = CGRectMake(50, 200, 220, 50);
    [button addTarget:self action:@selector(testMe:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];
}
@end


// Controller1.h:
#import <UIKit/UIKit.h>
#import "Controller2.h"
@interface Controller1 : UIViewController {
    Controller2                 *controller2;
    UINavigationController      *controller2navigationController;
    UIButton                    *button;
}
@end


// Controller1.m:
#import "Controller1.h"
@implementation Controller1
- (void)testMe:(id)target {
    controller2 = [[Controller2 alloc] init];
    controller2navigationController = [[UINavigationController alloc] initWithRootViewController:controller2];
    [self presentModalViewController:controller2navigationController animated:YES];
}
- (void)loadView {
    [super loadView];
    button = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain];
    [button setTitle:@"Test me 1" forState:UIControlStateNormal];
    button.frame = CGRectMake(50, 156, 220, 50);
    [button addTarget:self action:@selector(testMe:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];
    self.view.backgroundColor = [UIColor greenColor];
}
@end


// Controller2.h:
#import <UIKit/UIKit.h>
@interface Controller2 : UIViewController {
    UIButton                                *button;
}
@end


// Controller2.m:
#import "Controller2.h"
@implementation Controller2
- (void)testMe:(id)target {
    [self.parentViewController.parentViewController.parentViewController dismissModalViewControllerAnimated:YES];
}
- (void)loadView {
    [super loadView];
    button = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain];
    [button setTitle:@"Test me 2" forState:UIControlStateNormal];
    button.frame = CGRectMake(50, 156, 220, 50);
    [button addTarget:self action:@selector(testMe:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];
    self.view.backgroundColor = [UIColor redColor];
}
@end

Thanks for helping me find a solution to this problem.


You really shouldn't use such a big stack of viewcontrollers. The problem with this approach is that all those viewcontrollers stay in memory until you dismiss the first one which can cause memory warnings if those controllers get heavy.

If you still want to use that approach I would suggest using the delegate design pattern. So basically add a protocol for the first controller:

@protocol RootControllerDelegate

-(void) dismissModal;

@end

and assign a property to the next controllers

@property (nonatomic, assign) id <RootControllerDelegate> rootdelegate;

then just call [self.rootdelegate dismissModal] where you want them to disappear. This will visually look like only the last controller disappearing animated.

The better way to do this is making a RootViewController and adding the other viewcontrollers as subviews to it where you can remove them from memory when switching, see How does UITabBarController work?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜