不构建视图就不能以编程方式创建 UIViewController 吗?

Posted

技术标签:

【中文标题】不构建视图就不能以编程方式创建 UIViewController 吗?【英文标题】:Is it not possible to create a UIViewController programmatically without building the view? 【发布时间】:2015-06-12 17:21:52 【问题描述】:

我想以编程方式创建一个 UIViewController。没有笔尖或故事板。它基本上会被创建然后呈现,并在它自己的类中设置要显示的图像。

但是,每当我只是 alloc init 一个视图控制器并呈现它时,它就会在呈现时变成黑色。

我认为这是因为它缺乏自己的观点?

当我在 Storyboard 中创建原始 UIViewController 时,它会自动为其设置一个视图,我该如何设置该视图,使其像 Storyboard 一样具有正确的设备尺寸、旋转变化等?

【问题讨论】:

【参考方案1】:

希望这个答案在这里澄清了一些事情,即使已经有一个公认的答案。我觉得那里的解释不够清楚,这可能就是为什么 OP 一开始没有遵循它,导致 OP 更加混乱,并且回答者在 cmets 中变得尖刻,这对任何人都没有帮助。这不是这个网站的全部内容。

每当我只是分配初始化一个 [UIViewController] 并呈现它时,它就会在呈现时呈现黑色。

它实际上并不是黑色的。它是透明的(或者更准确地说,它的 view 是透明的)所以你真正看到的是来自视图后面的黑色(在这个简单的例子中,很可能是 UIWindow 本身。)

这是因为您在UIViewController 中依赖loadView 的默认实现,它只是创建了一个UIView 实例,而UIView 的背景属性默认为nil,因此它是透明的.但是,当您在界面生成器中进行设置时,它通常会为您将 backgroundColor 属性设置为白色。

您当然可以简单地自己在代码中执行此操作。这是一个示例,除了我使用绿色而不是白色之外,当你展示它时,你肯定知道你看到的是这个特定的视图:

UIViewController* plainViewController = [UIViewController new];
plainViewController.view.backgroundColor = [UIColor greenColor];

当然使用UIViewController 而不继承它没有多大意义,但你可以。您只需要在外部管理所有内容,就像我在上面所做的那样。

如果你子类UIViewController,你只需实现你自己的loadView实现来创建你自己的UIView(或子类),但请记住,它也是透明的,除非你也明确设置其backgroundColor。这里有一些方法可以做到这一点......

在你自己的UIViewController.m子类中,用默认的UIView实例初始化背景...

- (void) loadView

    [super loadView]; // Actually loads and assigns the default view

    // Set the background on the default view
    self.view.backgroundColor = [UIColor greenColor];

或者使用自定义的UIView 子类...

- (void) loadView

    // Create and initialize your custom view
    MyCustomUIView* myCustomUIView = [MyCustomUIView new];
    myCustomUIView.backgroundColor = [UIColor greenColor];

    // You're setting the view so do *not* call [super loadView]
    self.view = myCustomUIView;

您也可以在viewDidLoad 中初始化背景,就像这样(这适用于上述任何一个版本。

- (void) viewDidLoad

    // Set the background on whatever view is being managed
    // regardless of where/how it was created
    self.view.backgroundColor = [UIColor greenColor];

注意:使用viewDidLoad时:

    在上述第一种情况下,您可以完全删除 loadView,因为它不需要,因为 super 现在将处理创建视图。 在第二种情况下,您保留loadView,但删除您设置backgroundColor 属性的行,因为您现在正在viewDidLoad 中执行此操作。

然而,这三种方法的好处是现在视图的初始化包含在您的UIViewController 中,从而使重用变得更加容易。

附带说明,UIWindow 本身是UIView 的子类,因此它也有一个backgroundColor 属性(当然,默认情况下也是nil。)因此,如果你将窗口的backgroundColor 属性更改为紫色,这就是您所看到的而不是黑色(也就是说,直到您在视图上设置了背景颜色,它完全覆盖了窗口。)

我认为这是因为它缺乏自己的观点?

希望上述原因能澄清这种假设是错误的。它实际上就在那里,只是透明的。

简单地访问UIViewControllerview 属性的行为将创建视图(如果视图尚不存在)。由于呈现一个新实例化的UIViewController 需要访问它的view 属性才能实际呈现一些东西,即在创建视图时。但是,在上面我显式访问 view 属性以便我可以在其上设置 backgroundColor 属性的情况下,那个是创建视图的时间点。

无论如何,希望这能更清楚地说明您所看到的以及幕后实际发生的情况。一旦你掌握了它的窍门,它实际上非常简单地以编程方式创建和使用 ViewControllers。即便如此,通过 Interface Builder 使用故事板甚至 NIB 仍然要容易得多,因为您可以直观地看到自己在做什么。

【讨论】:

【参考方案2】:

但是,每当我只是分配初始化一个视图控制器并呈现它时,它就会在呈现时变成黑色。

因为它只是一个原始的 UIViewController。您无法修改/自定义它;这不是你的课。

相反,创建一个 UIViewController 子类,例如MyCoolViewController,并实例化并呈现 that。不同的是,使用 MyCoolViewController 可以覆盖viewDidLoad 和其他方法,以便在其view 中放入一些有用的接口。

如何将视图设置为像故事板一样,它是正确的设备尺寸、旋转变化等

别担心;所有这些都会自动发生,因为视图由视图控制器管理,并且视图控制器被正确放置在视图控制器层次结构中(例如,通过说 presentViewController:...)。

【讨论】:

我的书教你如何自定义一个视图控制器子类的视图,并给你一些代码来玩;从这里开始:apeth.com/iosBook/ch19.html#_manual_view 对不起,我的意思是说我正在使用一个子类。我用 alloc init 创建子类,呈现它,它是黑色的。我假设与自定义 UIPageViewController 子类不同,例如我必须自己设置?如何将视图指定为设备的正确大小并相应地旋转?我应该在 loadView 中这样做吗? 你没有。只需说presentViewController:... 就可以解决所有问题。视图控制器放入界面时视图的大小与视图控制器无关;由其父级处理。 我稍后会上传一个示例项目。我似乎正在这样做。 我的视图控制器出现了?它是黑色向我表明,因为当您添加没有自定义的视图控制器时,视图是白色的,所以一定有问题。我不在电脑旁,我没想到他们只是选择了不同的颜色。天哪。【参考方案3】:

来自documentation:

如果您无法在故事板或 nib 文件中定义视图, 重写 loadView 方法以手动实例化视图层次结构 并将其分配给视图属性。

【讨论】:

以上是关于不构建视图就不能以编程方式创建 UIViewController 吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何以编程方式创建控制器和 UIView 而不使用界面构建器? [关闭]

如何以编程方式设置控制图像视图宽度的滑块

以编程方式创建持久的 android 视图

Android 编程:如何以网格方式以编程方式创建各种视图类型

不能以编程方式DropDown按钮检查按钮标题

以编程方式创建的 UIViewController 加载界面构建器 view.xib 文件