如何在Objective中添加具有自己的UIViewController的子视图

我正在努力与自己的UIViewControllers子视图。 我有一个UIViewControllertoolbar上的视图(浅粉色)和两个按钮。 我想要在按下第一个按钮时显示蓝色视图,并按下第二个按钮时显示的黄色视图。 如果我只想显示一个视图,应该很容易。 但蓝色视图将包含一个表,所以它需要它自己的控制器。 那是我的第一课。 我从这个问题开始,在那里我学会了我需要一个控制器。

所以,我要回去在这里采取一些小步骤。 下面是我的Utility ViewController (主视图控制器)和其他两个控制器(蓝色和黄色)的简单起点的图片。 想象一下,当首次显示Utility ViewController (主视图)时,蓝色(默认)视图将显示在粉红色视图所在的位置。 用户将能够点击两个按钮前后来回,粉红色的视图将永远不会显示。 我只想让蓝色视图去粉色视图所在的位置,黄色视图去粉色视图所在的位置。 我希望这是有道理的。

简单的故事板图像

我试图使用addChildViewController 。 从我所看到的,有两种方法可以做到这一点:在storyboard的容器视图或编程的addChildViewController 。 我想以编程方式进行。 我不想使用NavigationController或Tab栏。 我只想添加控制器,并在按下相关按钮时将正确的视图推入粉色视图。

以下是我到目前为止的代码。 我想要做的就是显示粉红色视图所在的蓝色视图。 从我所看到的,我应该能够公正addChildViewController和addSubView。 这段代码不适合我。 我的困惑越来越好。 有人能帮助我在粉红色视图显示的地方显示蓝色视图吗?

除了在viewDidLoad中显示蓝色视图之外,此代码不用于执行任何操作。

IDUtilityViewController.h

#import <UIKit/UIKit.h>

@interface IDUtilityViewController : UIViewController
@property (strong, nonatomic) IBOutlet UIView *utilityView;
@end

IDUtilityViewController.m

#import "IDUtilityViewController.h"
#import "IDAboutViewController.h"

@interface IDUtilityViewController ()
@property (nonatomic, strong) IDAboutViewController *aboutVC;
@end

@implementation IDUtilityViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.aboutVC = [[IDAboutViewController alloc]initWithNibName:@"AboutVC" bundle:nil];
    [self addChildViewController:self.aboutVC];
    [self.aboutVC didMoveToParentViewController:self];
    [self.utilityView addSubview:self.aboutVC.aboutView];
}

@end

- - - - - - - - - - - - - 编辑 - - - - - - - - - - - - -------

self.aboutVC.aboutView是零。 但是我把它连接在storyboard 。 我还需要实例化吗?

在这里输入图像描述


这篇文章通常有最新的语法,比如Swift 4。

在今天的iOS中, “一切都是容器视图” 。 这是您今天制作应用的基本方式。

一个应用可能非常简单,只有一个视图。 但即使在这种情况下,屏幕上的每个“东西”都是一个容器视图。

这很简单...


(A)将容器视图拖入场景中...

将容器视图拖到场景视图中。 (就像你会拖入一个UIButton一样。)

容器视图是这张图片中的棕色东西。 它实际上是你的场景视图中。

在这里输入图像描述

将容器视图拖到场景视图中时,Xcode会自动给你两件事

  • 您可以在场景视图中获取容器视图,

  • 你会得到一个全新的UIViewController ,它只是坐在你的故事板上白色的某个地方

  • 这两个与“共济会的符号”的东西连接 -下面解释!


    (B)点击那个新的视图控制器(Xcode为你在白色区域的某个地方制作的新东西,而不是你场景中的东西)......并且改变这个类!

    这真的很简单。

    你完成了。


    这是视觉上解释的同样的事情。

    (A)注意容器视图

    (B)注意到控制器

    显示一个容器视图和相关的视图控制器

    点击B.(这是B - 不是A!)

    去右上角的检查员。 注意它说“UIViewController”

    [ 在这里输入图像描述 ] [3]

    将其更改为您自己的自定义类,这是一个UIViewController。

    在这里输入图像描述

    所以,我有一个Swift类Snap ,它是一个UIViewController

    在这里输入图像描述

    所以在Inspector中,我在“Snap”中输入“UIViewController”。

    (和往常一样,当您开始输入“Snap ...”时,Xcode会自动完成“Snap”)。)

    这就是它的全部 - 你完成了。


    如何改变容器视图 - 比如说一个表格视图。

    所以当你点击添加容器视图时,Apple会自动为你提供一个链接的视图控制器,坐在故事板上。

    恰巧(2017):默认情况下它使它成为UIViewController

    这很愚蠢:它应该问你需要哪种类型。 例如,你经常需要一个表格视图。 以下是如何将其改为不同的方式:

    在写这篇文章时,Xcode默认给你一个UIViewController 。 假设你想要一个UICollectionViewController来代替:

    (i)将容器视图拖入场景中。 看看Xcode默认给你的故事板上的UIViewController。

    (ii)将新的UICollectionViewController到故事UICollectionViewController白色区域的任何位置。

    (iii)点击场景中的容器视图。 点击连接检查器。 注意有一个“触发神论”。 将鼠标悬停在“触发的Segue”上,并注意到Xcode 突出显示了所有不需要的UIViewController。

    (iv)点击“x”实际删除触发的塞恩。

    (v) 触发的塞格拖动 (viewDidLoad是唯一的选择)。 将故事板拖到新的UICollectionViewController。 出现并弹出一个窗口。 您必须选择嵌入

    (vi)简单地删除所有不需要的UIViewController。 你完成了。

    短版本:删除不需要的UIViewController。 在故事板上放置一个新的UICollectionViewController 。 控制 - 从容器视图的连接 - 触发Segue - viewDidLoad拖动到您的新控制器。 一定要在弹出窗口中选择“嵌入”。


    输入文本标识符...

    你将有一个“方形方形”共鸣符号的东西:它在连接你的容器视图和视图控制器的“弯曲线”上。

    “共济会的象征”是赛格。

    在这里输入图像描述

    通过点击 “共济会的符号”的东西选择SEGUE。

    看你的权利。

    必须输入一个segue的文本标识符

    你决定这个名字。 它可以是任何文本字符串。 明智的选择通常是“segueClassName”。

    如果你遵循这个模式,你所有的segues将被称为segueClockView,seguePersonSelector,segueSnap,segueCards等等。

    接下来,你在哪里使用该文本标识符?


    如何连接'到'子控制器...

    然后,在代码中,在整个场景的ViewController中执行以下操作。

    假设您在场景中有三个容器视图。 每个容器视图都包含一个不同的控制器,例如“Snap”,“Clock”和“Other”。

    最新的Swift3语法(2017)

    var snap:Snap?
    var clock:Clock?
    var other:Other?
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if (segue.identifier == "segueSnap")
                { snap = (segue.destination as! Snap) }
        if (segue.identifier == "segueClock")
                { clock = (segue.destination as! Clock) }
        if (segue.identifier == "segueOther")
                { other = (segue.destination as! Other) }
    }
    

    就这么简单。 您使用prepareForSegue调用来连接变量以引用控制器。


    如何在'其他方向'连接到父母......

    假设你已经在容器视图中放置了控制器(示例中为“Snap”)。

    上面的“boss”视图控制器可能会让你感到困惑(例子中的“Dash”)。 幸运的是,这很简单:

    // Dash is the overall scene.
    // Here we are in Snap. Snap is one of the container views inside Dash.
    
    class Snap {
    
    var myBoss:Dash?    
    override func viewDidAppear(_ animated: Bool) { // MUST be viewDidAppear
        super.viewDidAppear(animated)
        myBoss = self.parent as? Dash
    }
    

    严重:只能从viewDidAppear或更高版本运行。 在viewDidLoad不起作用。

    你完成了。


    重要提示:只适用于容器视图。

    重要的高级技巧:不要忘记,只适用于容器视图。

    现在有了故事板标识符,在屏幕上弹出新视图(而不是在Android开发中)是司空见惯的事情。 所以,假设用户想编辑一些东西......

        // let's just pop a view on the screen.
        // this has nothing to do with container views
        //
        let e = ...instantiateViewController(withIdentifier: "Edit") as! Edit
        e.modalPresentationStyle = .overCurrentContext
        self.present(e, animated: false, completion: nil)
    

    在使用容器视图时, 保证 Dash将是Snap的父视图控制器。

    但是,当使用instantiateViewController时,这不是必需的

    非常容易混淆的是,在iOS中,父视图控制器实例化它的类无关 。 (它可能是相同的,但通常不一样。) self.parent模式适用于容器视图。

    (对于instantiateViewController模式中的类似结果,您必须使用一个协议和一个委托,记住委托将是一个薄弱环节。)


    prepareForSegue命名不佳...

    值得注意的是,“准备赛报”是一个非常糟糕的名字!

    “prepareForSegue”用于两个目的:加载容器视图,以及在场景之间延续。

    但在实践中,你很少在场景之间流连忘返! 几乎所有的应用程序都有许多容器视图。

    如果“prepareForSegue”被称为“loadingContainerView”,那将会更有意义。


    超过一个...

    常见的情况是:屏幕上有一个小区域,您想在其中显示多个不同视图控制器中的一个。 例如,四个小部件之一。

    最简单的方法:只有四个不同的容器视图都坐在同一个区域 。 在你的代码中,只需隐藏所有四个并打开你想看到的那个。

    在故事板上,有一个空的“持有人”UIView,它只保存四个容器视图。 然后,您可以通过调整或移动“支架”来一次调整或移动所有四个尺寸。 在你的代码中,只需要有四个UIView插座,每个容器视图都有一个插座。 复制并粘贴上面的代码,“如何连接到子控制器”,以连接四个包含的视图控制器。


    注意 - Storyboard参考文件到达!

    正如SimplGy在下面指出的那样:“iOS 9的Storyboard引用使得容器视图更加可怕,您可以在任何地方定义可重用视图(控制器),并在多个模块化故事板中的任何容器视图中引用它。

    还要注意 - 相当容易混淆 - 通常今天你只是不打扰容器视图!

    在许多情况下,您只需instantiateViewController#withIdentifier

    但请注意上面解释的关于.parent的“gotchya”。 容器视图的全部内容是您可以即时且简单地确定父链。

    如果你使用instantiateViewController#withIdentifier使用storyboard引用,你必须instantiateViewController#withIdentifier协议和委托(记住委托将是一个薄弱的环节)。 但是,你可以随时随地灵活使用它。

    相比之下,使用“固定”,可以说,容器视图非常简单,您可以立即在父母和孩子之间进行连接,如上所述。


    我看到两个问题。 首先,因为你正在做的故事板的控制器,你应该和他们实例instantiateViewControllerWithIdentifier:initWithNibName:bundle: 。 其次,将视图添加为子视图时,应该给它一个框架。 所以,

    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        self.aboutVC = [self.storyboard instantiateViewControllerWithIdentifier:@"aboutVC"]; // make sure you give the controller this same identifier in the storyboard
        [self addChildViewController:self.aboutVC];
        [self.aboutVC didMoveToParentViewController:self];
        self.aboutVC.view.frame = self.utilityView.bounds;
        [self.utilityView addSubview:self.aboutVC.aboutView];
    }
    
    链接地址: http://www.djcxy.com/p/2519.html

    上一篇: How to add a subview that has its own UIViewController in Objective

    下一篇: What attributes does bgcolor support