View Controller:如何以编程方式在视图之间切换?

时间:2009-05-26 14:30:15

标签: iphone uikit uiviewcontroller uitabbarcontroller

简而言之:我希望有两个全屏视图,我可以在视图A和视图B之间切换。我知道我可以使用标签栏控制器,但我不想这样做。我想看看这是如何手工完成的,以了解幕后发生的事情。

我有一个充当根控制器的UIViewController:

@interface MyRootController : UIViewController {
    IBOutlet UIView *contentView;
}
@property(nonatomic, retain) UIView *contentView;

@end

将contentView连接到UIView,我将其作为子视图添加到Nib的“视图”中。这有绿色,我看到它全屏。工作正常。

然后,我以非常相同的方式创建了另外两个View Controller。 ViewControllerA和ViewControllerB。 ViewControllerA有蓝色背景,ViewControllerB有黑色背景。只是看看哪一个是活跃的。

所以,在myRootController的实现中,我这样做:

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];

    ViewControllerA *vcA = [[ViewControllerA alloc] initWithNib];
    [self.contentView addSubview:vcA.view];

    [cvA release];
}

顺便说一句,-initWithNib方法如下所示:

- (id)initWithNib { // Load the view nib
    if (self = [super initWithNibName:@"ViewA" bundle:nil]) {
        // do ivar initialization here, if needed
    }
    return self;
}

有效。当我启动应用程序时,我会看到ViewControllerA中的视图。但现在最大的问题是:View Controller通常具有以下所有方法:

  • (无效)viewWillAppear中:(BOOL)动画;
  • (无效)viewDidDisappear:(BOOL)动画;
  • (无效)viewDidLoad中;

......等等。如果我在没有标签栏控制器的情况下以“我的”方式进行操作,那么这些方法是谁或者是什么?我的意思是:如果我分配了ViewController的类并且视图得到可见,我是否需要注意调用这些方法?它是如何知道viewWillAppear,viewDidDisappear或viewDidLoad的?我相信标签栏控制器具有所有这些“聪明”的内幕。或者我错了吗?

更新:我已经测试过了。如果我释放视图控制器(例如:ViewControllerA),我将在viewDidDisappear上没有日志消息。只有在分配和初始化ViewControllerA时,我才会得到一个viewDidLoad。但就是这样。所以所有迹象都代表着UITabBarController的聪明之处;)我必须弄清楚如何复制它,对吗?

4 个答案:

答案 0 :(得分:50)

在Beginning iPhone Development的第6章中有一个很好的切换视图的例子。你可以在这里看到它的源代码: http://iphonedevbook.com/

SwitchViewController具有以编程方式更改视图的代码。


- (IBAction)switchViews:(id)sender
{

    if (self.yellowViewController == nil)
    {
        YellowViewController *yellowController = [[YellowViewController alloc]
                initWithNibName:@"YellowView" bundle:nil];
        self.yellowViewController = yellowController;
        [yellowController release];
    }

    [UIView beginAnimations:@"View Flip" context:nil];
    [UIView setAnimationDuration:1.25];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];

    UIViewController *coming = nil;
    UIViewController *going = nil;
    UIViewAnimationTransition transition;

    if (self.blueViewController.view.superview == nil) 
    {   
        coming = blueViewController;
        going = yellowViewController;
        transition = UIViewAnimationTransitionFlipFromLeft;
    }
    else
    {
        coming = yellowViewController;
        going = blueViewController;
        transition = UIViewAnimationTransitionFlipFromRight;
    }

    [UIView setAnimationTransition: transition forView:self.view cache:YES];
    [coming viewWillAppear:YES];
    [going viewWillDisappear:YES];
    [going.view removeFromSuperview];
    [self.view insertSubview: coming.view atIndex:0];
    [going viewDidDisappear:YES];
    [coming viewDidAppear:YES];

    [UIView commitAnimations];

}

答案 1 :(得分:39)

您可以从最简单的removeFromSuperview / insertSubview开始,一点一点地添加代码。


//SwitchViewController.h
#import 
@class BlueViewController;
@class YellowViewController;

@interface SwitchViewController : UIViewController {
    IBOutlet BlueViewController *blueViewController;
    IBOutlet YellowViewController *yellowViewController;
}
- (IBAction)switchViews:(id)sender;
@property (nonatomic, retain) BlueViewController *blueViewController;
@property (nonatomic, retain) YellowViewController *yellowViewController;
@end

//1. remove yellow view and insert blue view
- (IBAction)switchViews:(id)sender {
    if(self.blueViewController.view.superview == nil)
    {
        [yellowViewController.view removeFromSuperview];
        [self.view insertSubview:blueViewController.view atIndex:0];
    }
}

//2. appear=insert, disappear=remove
if(blueViewController.view.superview == nil)
{
    [blueViewController viewWillAppear:YES];
    [yellowViewController viewWillDisappear:YES];

    [yellowViewController.view removeFromSuperview];
    [self.view insertSubview:self.blueViewController.view atIndex:0];

    [yellowViewController viewDidDisappear:YES];
    [blueViewController viewDidAppear:YES];
}

//3. now add animation
[UIView beginAnimations:@"View Flip" context:nil];
[UIView setAnimationDuration:1.25];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
//blue view will appear by flipping from right
if(blueViewController.view.superview == nil)
{
    [UIView setAnimationTransition: UIViewAnimationTransitionFlipFromRight 
                            forView:self.view cache:YES];

    [blueViewController viewWillAppear:YES];
    [yellowViewController viewWillDisappear:YES];

    [yellowViewController.view removeFromSuperview];
    [self.view insertSubview:self.blueViewController.view atIndex:0];

    [yellowViewController viewDidDisappear:YES];
    [blueViewController viewDidAppear:YES];
}
[UIView commitAnimations];

答案 2 :(得分:21)

如果我理解正确,你想要完成的事情非常简单。

只需在您的应用程序委托上添加UINavigationController并执行:

[navigationController pushView:vcA];

将相应调用代表:

  • (无效)viewWillAppear中:(BOOL)动画;
  • (无效)viewDidDisappear:(BOOL)动画;
  • (无效)viewDidLoad中;

当您想要弹出视图并推送另一个视图时:

[navigationController popViewControllerAnimated:true];
[navigationController pushView:vcB];

如果您不希望导航控制器只显示使用:

[navigationBar setHidden:YES];

其中navigationBar是与您的UINavigationController对应的UINavigationBar。

答案 3 :(得分:2)

这可能是一个老问题,但我最近遇到了同样的问题,并且很难找到有用的东西。我想在两个互补的视图控制器之间切换,但我希望开关是动画的(内置动画工作正常),我希望它尽可能与故事板兼容。

为了利用内置过渡,UIView的+transitionFromView:toView:duration:options:completion:方法运行得非常好。但是,它只在视图之间转换,而不是视图控制器。

要在整个视图控制器之间进行转换,而不仅仅是视图,创建自定义UIStoryboardSegue是最佳选择。无论您是否使用故事板,此方法都可以封装整个转换并管理从一个视图控制器到下一个视图控制器的相关信息的传递。它只涉及对UIStoryboardSegue进行子类化并覆盖单个方法-perform

有关参考实现,请参阅RAFlipReplaceSegue,我使用此方法整理的确切自定义segue。作为奖励,它还将旧视图控制器替换为新视图控制器,如果它位于UINavigationController堆栈中。