在iOS中使用选项卡更改容器视图内容

Cli*_*rum 16 ios xcode-storyboard container-view

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

查看控制器

标签1 =查看控制器1

标签2 =查看控制器2

标签3 =查看控制器3

上面显示的视图控制器具有PPAddEntryViewController.m类.我在这个类中创建了一个Container视图的插座,现在有一个Container View属性:

@property (weak, nonatomic) IBOutlet UIView *container;
Run Code Online (Sandbox Code Playgroud)

我也为我的标签准备了IBActions:

- (IBAction)tab1:(id)sender {
  //...
}
- (IBAction)tab2:(id)sender {
  //...
}
- (IBAction)tab3:(id)sender {
  //...
}
Run Code Online (Sandbox Code Playgroud)

如何在这些IBActions中设置容器以更改容器视图包含的视图控制器?

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

UIViewController *viewController1 = [self.storyboard instantiateViewControllerWithIdentifier:@"vc1"];
_container.view = viewController1;
Run Code Online (Sandbox Code Playgroud)

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

Cam*_*mer 16

使用故事板切换,自动布局与否,某种按钮以及一系列子视图控制器

您希望将容器视图添加到视图中,并且当按下"切换"子视图控制器的按钮时,将触发相应的segue并执行正确的设置工作.

在Storyboard中,您只能将一个Embed Segue连接到Container View.所以你创建了一个中间处理控制器.使嵌入segue并为其指定标识符,例如EmbededSegueIdentifier.

在父视图控制器中,连接按钮或任何您想要的内容,并在prepare segue中引用您的子视图控制器.一旦父视图控制器加载segue将被触发.

父视图控制器

@property (weak, nonatomic) MyContainerViewController *myContainerViewController;

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

您可以很容易地按下按钮按下容器控制器.

容器控制器

下一部分代码部分借用了几个来源,但关键的变化是使用自动布局而不是显式帧.没有什么阻止你只是改变了线[self addConstraintsForViewController:]viewController.view.frame = self.view.bounds.在故事板中,此容器视图控制器不会执行任何与目标子视图控制器相关的操作.

- (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;
    }
}
Run Code Online (Sandbox Code Playgroud)

自定义细分

您需要的最后一件事是一个不做任何事情的自定义segue,使用从Container View Controller调用的相应segue标识符到达每个目标.如果你没有放入一个空的执行方法,应用程序将崩溃.通常你可以在这里做一些自定义过渡动画.

@implementation SHCDummySegue

@interface SHCDummySegue : UIStoryboardSegue

@end

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

@end
Run Code Online (Sandbox Code Playgroud)

  • 非常好的通用解决方案,不仅适用于替换UITabbarController! (2认同)

Cli*_*rum 11

我最近找到了我想要做的完美示例代码.它包括Storyboard实现和所有相关的segue和代码.这真的很有帮助.

https://github.com/mhaddl/MHCustomTabBarController


Rog*_*ger 7

更新:UITabBarController是推荐的方法,正如您之前发现的那样.如果你想要一个自定义高度,这是一个很好的开始:我自定义UITabBarController的tabbar的方式 - Stackoverflow答案

从iOS 5+开始,您可以通过此API自定义外观; UIAppearance协议参考.这是一个很好的教程:如何自定义标签栏背景和外观

实现您正在寻找的最明显的方法是简单地管理3个不同的容器(它们是简单的UIViews)并实现它们中的每一个以保存每个选项卡所需的任何内容视图(使用容器的隐藏属性).

以下是使用不同容器实现的示例:

嵌入视图控制器

这些容器"交换"当然可以动画.关于你的自我答案,你可能选择了正确的方法来做到这一点.