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

Is it not possible to create a UIViewController programmatically without building the view?

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

但是,每当我只是 alloc init 一个视图控制器并显示它时,它在显示时显示为黑色。

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

当我在 Storyboard 中创建原始 UIViewController 时,它会自动为其设置一个视图,我如何将视图设置为像 Storyboard 一样具有适当的设备大小、旋转变化等?

However, whenever I just alloc init a view controller and present it, it comes out black as it is presented.

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

相反,创建一个 UIViewController subclass,例如MyCoolViewController,并实例化并呈现 that。不同之处在于,使用 MyCoolViewController 您可以覆盖 viewDidLoad 和其他方法,以便将一些有用的接口放入其 view.

how do I set the view up so like the Storyboard it's the proper device size, changes on rotation, etc

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

来自documentation

If you cannot define your views in a storyboard or a nib file, override the loadView method to manually instantiate a view hierarchy and assign it to the view property.

希望这个答案能澄清一些事情,即使已经有一个被接受的答案。我觉得给出的解释不够清楚,这可能是 OP 一开始没有遵循它的原因,导致 OP 更加混乱,回答者在评论中变得尖刻,这对任何人都没有帮助。这不是本网站的全部内容。

Whenever I just alloc init a [UIViewController] and present it, it comes out black as it is presented.

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

这是因为您依赖 UIViewControllerloadView 的默认实现,它只是创建一个 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时:

  1. 在上面的第一种情况下,您可以完全删除 loadView,因为不需要 super 现在将处理创建视图。
  2. 在第二种情况下,您离开 loadView 但删除设置 backgroundColor 属性 的行,因为您现在在 viewDidLoad 中这样做.

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

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

I assume this is because it lacks its own view?

希望以上的理由说明这个假设是错误的。它确实存在,只是透明。

如果视图不存在,只需访问 UIViewControllerview 属性 即可创建视图。由于呈现新实例化的 UIViewController 需要访问其 view 属性 才能实际呈现某些内容,即创建视图时。但是,在上述情况下,我明确访问了 view 属性,因此我可以在其上设置 backgroundColor 属性,that是创建视图的时间点。

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