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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16330195/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 23:24:51  来源:igfitidea点击:

Change Container View Content with Tabs in iOS

iosxcode-storyboardcontainer-view

提问by Clifton Labrum

I'm trying to make a form that spans three tabs. You can see in the screenshot below where the tabs will be. When the user taps a tab, the Container View should update and show a particular view controller I have.

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

view controller

视图控制器

Tab 1 = View Controller 1

选项卡 1 = 视图控制器 1

Tab 2 = View Controller 2

选项卡 2 = 视图控制器 2

Tab 3 = View Controller 3

选项卡 3 = 视图控制器 3

The view controller shown above has the class PPAddEntryViewController.m. I created an outlet for the Container view within this class and now have a Container View property:

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

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

I also have my IBActions for my tabs ready:

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

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

How do I set the container in those IBActions to change the view controller that the Container View holds?

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

Among a few other things, here's what I've tried:

除其他几件事外,这是我尝试过的:

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

...but it doesn't work. Thanks in advance.

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

采纳答案by Clifton Labrum

I recently found the perfectsample code for what I was trying to do. It includes the Storyboard implementation and all the relevant segues and code. It was really helpful.

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

https://github.com/mhaddl/MHCustomTabBarController

https://github.com/mhaddl/MHCustomTabBarController

回答by Cameron Lowell Palmer

Switching using Storyboard, Auto-layout or not, a Button of some sort, and a series of Child View Controllers

使用 Storyboard 切换、是否自动布局、某种 Button 和一系列子视图控制器

You want to add the container view to your view and when the buttons that 'switch' child view controllers are pressed fire off the appropriate segue and perform the correct setup work.

您想将容器视图添加到您的视图中,当按下“切换”子视图控制器的按钮时,会触发适当的转场并执行正确的设置工作。

In the Storyboard you can only connect one Embed Segue to the Container View. So you create an intermediate handling controller. Make the embed segue and give it an identifier, for example EmbededSegueIdentifier.

在 Storyboard 中,您只能将一个 Embed Segue 连接到容器视图。所以你创建了一个中间处理控制器。制作 embed segue 并给它一个标识符,例如 EmbededSegueIdentifier。

In your parent view controller wire up the button or whatever you want and keep are reference to your child view controller in the prepare segue. As soon as the parent view controller loads the segue will be fired.

在您的父视图控制器中,将按钮或任何您想要并保留的内容连接到准备转场中对您的子视图控制器的引用。一旦父视图控制器加载,segue 就会被触发。

The Parent View Controller

父视图控制器

@property (weak, nonatomic) MyContainerViewController *myContainerViewController;

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

It should be fairly easy for you to delegate to your container controller the button presses.

您应该很容易将按下的按钮委托给容器控制器。

The Container Controller

容器控制器

This next bit of code was partly borrowed from a couple of sources, but the key change is that auto layout is being used as opposed to explicit frames. There is nothing preventing you from simply changing out the lines [self addConstraintsForViewController:]for viewController.view.frame = self.view.bounds. In the Storyboard this Container View Controller doesn't do anything more that segue to the destination child view controllers.

下面的代码部分是从几个来源借用的,但关键的变化是使用了自动布局而不是显式框架。没有什么阻止你只是改变了线[self addConstraintsForViewController:]viewController.view.frame = self.view.bounds。在 Storyboard 中,这个容器视图控制器不会做任何与目标子视图控制器相关的事情。

- (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;
    }
}

The Custom Segues

自定义转场

The last thing you need is a custom segue that does nothing, going to each destination with the appropriate segue identifier that is called from the Container View Controller. If you don't put in an empty perform method the app will crash. Normally you could do some custom transition animation here.

您需要的最后一件事是自定义 segue,它什么都不做,使用从容器视图控制器调用的适当 segue 标识符到达每个目的地。如果你不输入一个空的 perform 方法,应用程序就会崩溃。通常你可以在这里做一些自定义的过渡动画。

@implementation SHCDummySegue

@interface SHCDummySegue : UIStoryboardSegue

@end

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

@end

回答by Roger

Update: UITabBarController is the recommended way to go, as you found out earlier. In case you'd like to have a custom height, here is a good start: My way of customizing UITabBarController's tabbar - Stackoverflow answer

更新: UITabBarController 是推荐的方法,正如您之前发现的那样。如果您想要自定义高度,这是一个好的开始:我自定义 UITabBarController 的标签栏的方式 - Stackoverflow answer

As of iOS 5+ you have access to customize the appearance via this API; UIAppearance Protocol Reference. Here is a nice tutorial for that: How To Customize Tab Bar Background and Appearance

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

The most obvious way to achieve what you're looking for is to simply manage 3 different containers (they are simple UIViews) and implement each of them to hold whatever content view you need for each tab (use the hidden property of the containers).

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

Here is an exampleof what's possible to achieve with different containers:

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

Embed View Controllers

嵌入视图控制器

These containers "swapping" can be animated of course. About your self-answer, you probably chose the right way to do it.

这些容器“交换”当然可以动画化。关于你的自我回答,你可能选择了正确的方法。

回答by Daij-Djan

have a member variable to hold the viewController:

有一个成员变量来保存 viewController:

UIViewController *selectedViewController;

now in the IBActions, switch that AND the view. e.g.

现在在 IBActions 中,切换它和视图。例如

- (IBAction)tab1:(id)sender {
     UIViewController *viewController1 = [self.storyboard instantiateViewControllerWithIdentifier:@"vc1"];

     _container.view = viewController1.view;
     selectedViewController = viewController1;
}


to fire view did appear and stuff call removeChildViewController, didMoveToParent, addChildViewController, didMoveToParent

触发视图确实出现并且东西调用 removeChildViewController, didMoveToParent, addChildViewController, didMoveToParent

回答by Clifton Labrum

I got this to work by using a UITabBarController. In order to use custom tabs, I had to subclass the TabBarController and add the buttons to the controller in code. I then listen for tap events on the buttons and set the selectedIndexfor each tab.

我通过使用 UITabBarController 使其工作。为了使用自定义选项卡,我必须继承 TabBarController 并在代码中将按钮添加到控制器。然后我监听按钮上的点击事件并selectedIndex为每个选项卡设置。

It was pretty straight forward, but it's a lot of junk in my Storyboard for something as simple as 3 tabs.

它非常简单,但是对于像 3 个标签这样简单的东西,我的故事板中有很多垃圾。