如果您在 iOS 5 世界中并想在各种视图控制器之间跳转,您可能想要追求View Controller Containment。或查看WWDC 2011 会议 102。
视图控制器包含基本上假设您有一些父视图控制器来管理多个子控制器之间的导航。在您的情况下,父视图将是一个带有导航栏和按钮的视图。
更新:
如果你追求遏制,你可以创建一个父视图控制器,它有一个带有按钮的导航栏。当您加载该视图时,您可以添加第一个子视图。因此viewDidLoad
可能看起来像:
- (void)viewDidLoad
{
[super viewDidLoad];
// this is my model, where I store data used by my view controllers
_model = [[MyModel alloc] init];
// let's create our first view controller
OneViewController *controller = [[OneViewController alloc] initWithNibName:@"OneViewController" bundle:nil];
// pass it our model (obviously, `model` is a property that I've set up in my child controllers)
controller.model = _model;
// let's put the new child in our container and add it to the view
[self addChildViewController:controller];
[self configureChild:controller];
[self.view addSubview:controller.view];
[controller didMoveToParentViewController:self];
// update our navigation bar title and the label of the button accordingly
[self updateTitles:controller];
}
configureChild
只是做最后的配置。为方便起见,我经常会在 IB 中设置一个 UIView(在本例中称为childView
),用于设置框架,这让我摆脱了手动创建框架的世界,但是可以随心所欲:
- (void)configureChild:(UIViewController *)controller
{
// configure it to be the right size (I create a childView in IB that is convenient for setting the size of the views of our child view controllers)
controller.view.frame = self.childView.frame;
}
如果您触摸导航栏中的按钮,就会执行此操作。如果您在第一个控制器中,请设置第二个控制器。如果您在第二个控制器中,请设置第一个:
- (IBAction)barButtonTouchUpInside:(id)sender
{
UIViewController *currentChildController = [self.childViewControllers objectAtIndex:0];
if ([currentChildController isKindOfClass:[OneViewController class]])
{
TwoViewController *newChildController = [[TwoViewController alloc] initWithNibName:@"TwoViewController" bundle:nil];
newChildController.model = _model;
[self transitionFrom:currentChildController To:newChildController];
}
else if ([currentChildController isKindOfClass:[TwoViewController class]])
{
OneViewController *newChildController = [[OneViewController alloc] initWithNibName:@"OneViewController" bundle:nil];
newChildController.model = _model;
[self transitionFrom:currentChildController To:newChildController];
}
else
NSAssert(FALSE, @"Unknown controller type");
}
这完成了基本的转换(包括各种与收容相关的调用):
- (void)transitionFrom:(UIViewController *)oldController To:(UIViewController *)newController
{
[self addChildViewController:newController];
[self configureChild:newController];
[self transitionFromViewController:oldController
toViewController:newController
duration:0.5
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
[self updateTitles:newController];
}
completion:^(BOOL finished){
[oldController willMoveToParentViewController:nil];
[oldController removeFromParentViewController];
[newController didMoveToParentViewController:self];
}];
}
此方法只是根据选择的子视图在父视图控制器的导航栏中设置标题。它还设置按钮以引用另一个控制器。
- (void)updateTitles:(UIViewController *)controller
{
if ([controller isKindOfClass:[OneViewController class]])
{
self.navigationItemTitle.title = @"First View Controller"; // current title
self.barButton.title = @"Two"; // title of button to take me to next controller
}
else if ([controller isKindOfClass:[TwoViewController class]])
{
self.navigationItemTitle.title = @"Second View Controller"; // current title
self.barButton.title = @"One"; // title of button to take me to next controller
}
else
NSAssert(FALSE, @"Unknown controller type");
}
这一切都假设您将在控制器之间跳转时创建和销毁控制器。我通常这样做,但使用模型对象来存储我的数据,所以我保留我想要的任何数据。
您说您不想“不重新分配和替换 UIViews”来执行此操作:如果是这样,您还可以更改上面的代码以预先创建两个子视图控制器并将转换更改为在它们之间简单地跳转:
- (void)viewDidLoad
{
[super viewDidLoad];
// this is my model, where I store data used by my view controllers
_model = [[MyModel alloc] init];
// let's create our first view controller
_controller0 = [[OneViewController alloc] initWithNibName:@"OneViewController" bundle:nil];
_controller0.model = _model;
[self addChildViewController:_controller0];
[self configureChild:_controller0];
[_controller0 didMoveToParentViewController:self];
// let's create our second view controller
_controller1 = [[OneViewController alloc] initWithNibName:@"OneViewController" bundle:nil];
_controller1.model = _model;
[self addChildViewController:_controller1];
[self configureChild:_controller1];
[_controller1 didMoveToParentViewController:self];
// let's add the first view and update our navigation bar title and the label of the button accordingly
_currentChildController = _controller0;
[self.view addSubview:_currentChildController.view];
[self updateTitles:_currentChildController];
}
- (void)transitionFrom:(UIViewController *)oldController To:(UIViewController *)newController
{
[self transitionFromViewController:oldController
toViewController:newController
duration:0.5
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
[self updateTitles:newController];
}
completion:^(BOOL finished){
_currentChildController = newController;
}];
}
- (IBAction)barButtonTouchUpInside:(id)sender
{
UIViewController *newChildController;
if ([_currentChildController isKindOfClass:[OneViewController class]])
{
newChildController = _controller1;
}
else if ([_currentChildController isKindOfClass:[TwoViewController class]])
{
newChildController = _controller0;
}
else
NSAssert(FALSE, @"Unknown controller type");
[self transitionFrom:_currentChildController To:newChildController];
}
我已经看到了这两种方式,所以你可以做任何适合你的事情。