ios - 在 iOS 中使用选项卡更改容器 View 内容

标签 ios xcode-storyboard container-view

我正在尝试制作一个跨越三个选项卡的表单。您可以在下面的屏幕截图中看到选项卡所在的位置。当用户点击一个选项卡时,容器 View 应该更新并显示我拥有的特定 View Controller 。

view controller

Tab 1 = View Controller 1

Tab 2 = View Controller 2

选项卡 3 = View Controller 3

上面显示的 View Controller 具有 PPAddEntryViewController.m 类。我在此类中为容器 View 创建了一个导出,现在有一个容器 View 属性:

@property (weak, nonatomic) IBOutlet UIView *container;

我的选项卡的 IBActions 也已准备就绪:

- (IBAction)tab1:(id)sender {
  //...
}
- (IBAction)tab2:(id)sender {
  //...
}
- (IBAction)tab3:(id)sender {
  //...
}

如何在这些 IBAction 中设置容器以更改容器 View 持有的 View Controller ?

在其他一些事情中,这是我尝试过的:

UIViewController *viewController1 = [self.storyboard instantiateViewControllerWithIdentifier:@"vc1"];
_container.view = viewController1;

...但是它不起作用。提前致谢。

最佳答案

使用 Storyboard、自动布局或不自动布局、某种按钮和一系列 subview Controller 进行切换

您想将容器 View 添加到您的 View 中,当按下“切换” subview Controller 的按钮时,会触发适当的 segue 并执行正确的设置工作。

在 Storyboard 中,您只能将一个 Embed Segue 连接到 Container View。所以你创建了一个中间处理 Controller 。制作嵌入转场并给它一个标识符,例如 EmbededSegueIdentifier。

在您的父 View Controller 中,连接按钮或任何您想要的东西,并在 prepare segue 中保留对您的 subview Controller 的引用。一旦父 View Controller 加载,segue 就会被触发。

父 View Controller

@property (weak, nonatomic) MyContainerViewController *myContainerViewController;

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"EmbeddedSegueIdentifier"]) {
        self.myContainerViewController = segue.destinationViewController;
    }
}

您应该很容易将按下按钮的操作委派给您的容器 Controller 。

容器 Controller

下一段代码部分是从几个来源借用的,但关键的变化是使用自动布局而不是显式框架。没有什么可以阻止您简单地将 [self addConstraintsForViewController:] 行更改为 viewController.view.frame = self.view.bounds。在 Storyboard 中,此容器 View Controller 不会做任何与目标 subview Controller 相关的事情。

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSLog(@"%s", __PRETTY_FUNCTION__);

    [self performSegueWithIdentifier:@"FirstViewControllerSegue" sender:nil];
}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    UIViewController *destinationViewController = segue.destinationViewController;

    if ([self.childViewControllers count] > 0) {
        UIViewController *fromViewController = [self.childViewControllers firstObject];
        [self swapFromViewController:fromViewController toViewController:destinationViewController];
    } else {
        [self initializeChildViewController:destinationViewController];
    }
}

- (void)initializeChildViewController:(UIViewController *)viewController
{
    [self addChildViewController:viewController];
    [self.view addSubview:viewController.view];
    [self addConstraintsForViewController:viewController];

    [viewController didMoveToParentViewController:self];
}

- (void)swapFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController
{
    [fromViewController willMoveToParentViewController:nil];
    [self addChildViewController:toViewController];
    [self transitionFromViewController:fromViewController toViewController:toViewController duration:0.2f options:UIViewAnimationOptionTransitionCrossDissolve animations:nil completion:^(BOOL finished) {
        [self addConstraintsForViewController:toViewController];
        [fromViewController removeFromParentViewController];
        [toViewController didMoveToParentViewController:self];
    }];
}

- (void)addConstraintsForViewController:(UIViewController *)viewController
{
    UIView *containerView = self.view;
    UIView *childView = viewController.view;
    [childView setTranslatesAutoresizingMaskIntoConstraints:NO];
    [containerView addSubview:childView];

    NSDictionary *views = NSDictionaryOfVariableBindings(childView);
    [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[childView]|"
                                                                          options:0
                                                                          metrics:nil
                                                                            views:views]];
    [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[childView]|"
                                                                          options:0
                                                                          metrics:nil
                                                                            views:views]];
}



#pragma mark - Setters

- (void)setSelectedControl:(ViewControllerSelectionType)selectedControl
{
    _selectedControl = selectedControl;

    switch (self.selectedControl) {
        case kFirstViewController:
            [self performSegueWithIdentifier:@"FirstViewControllerSegue" sender:nil];
            break;
        case kSecondViewController:
            [self performSegueWithIdentifier:@"SecondViewControllerSegue" sender:nil];
            break;
        default:
            break;
    }
}

自定义转场

您最不需要的是一个不执行任何操作的自定义转场,使用从容器 View Controller 调用的适当转场标识符到达每个目的地。如果您不放入空的执行方法,应用程序将会崩溃。通常你可以在这里做一些自定义的过渡动画。

@implementation SHCDummySegue

@interface SHCDummySegue : UIStoryboardSegue

@end

- (void)perform
{
    // This space intentionally left blank
}

@end

关于ios - 在 iOS 中使用选项卡更改容器 View 内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16330195/

相关文章:

objective-c - 具有字符串常量和 id 的 NSDictionary

swift - 当样式为 .compact 时,选择后关闭 UIDatePicker

ios - 通过 TabBar 链接两个 TableView

ios - UITableView 页脚、 Storyboard和 Xcode 6 的自动布局问题

ios - 将 subview Controller 的 View 添加到父 View Controller 的 subview

objective-c - 容器 View Controller 状态栏 iOS 7

iphone - 在 iOS 中暂停/静音背景音乐

ios - 添加 UICollectionView 后 iOS 9 中的自定义键盘崩溃

ios - 代码 : Missing arm64 Symbols from MagTek iOS Library

uitableview - 自动布局 : How to compress a complex popover