iOS如何不从源代码将多个viewController添加到一个ViewController

发布于 2025-01-03 13:35:18 字数 840 浏览 2 评论 0原文

我遇到了一些问题,因为我不知道如何做到这一点。请有人帮助我。

问题:

当我在 Xcode 中创建新项目时,我有一个带有 UIViewController 类的项目,并且一直创建。在这个 viewController 中,我有一个用于在 Xcode 中设计的 xib 文件。

start new project

我需要的是创建一些视图并在 Interface Builder 中设计它们,如下所示:

一些视图

但我需要这些视图是 UIViewController,而不是 UIView。

该项目应如下所示: 在此处输入图像描述

所以我不知道如何在 IB 中执行此操作,但我可以从源代码中执行此操作ViewController.m

tab  = [[TabBarController alloc] initWithNibName:@"mytestview" bundle:nil];
    [tab.view setFrame:CGRectMake(100, 100, 400, 600)];
    [self.view addSubview:tab.view];

但这不是我的视图,它是一个不同的对象,如果我想更改位置或大小,我必须通过代码来完成。我如何在 Interface Builder 中做同样的事情?

I'm having some problems because I don't know how it can be done. Someone help me please.

Problem:

I have a project with a UIViewController class with created all time when I create a new project in Xcode. In this viewController, I have a xib file for designing in Xcode.

start new project

What I need is to create some views and design them in Interface Builder like this:

some views

But I need these views to be UIViewControllers, not UIViews.

The project should look like:
enter image description here

So I don't know how I can do this in IB but I can do it from source code in ViewController.m

tab  = [[TabBarController alloc] initWithNibName:@"mytestview" bundle:nil];
    [tab.view setFrame:CGRectMake(100, 100, 400, 600)];
    [self.view addSubview:tab.view];

But it's not my views it's a different object, and if I want to change position or size I must do it from code. How I can do same things in Interface Builder?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦里的微风 2025-01-10 13:35:19

让我们考虑以下基于仅适用于 iPhone 的主详细应用程序的示例。

因此,在 Xcode 中新创建的项目中添加新的视图控制器:
在此处输入图像描述

我将其命名为 NewInsideViewController。不使用 xib 创建它:
在此处输入图像描述

打开 DetailViewController.xib。将视图控制器和视图(*)对象从库拖到对象区域,如下所示(我将视图的颜色更改为浅灰色):
在此处输入图像描述

选择此视图控制器并在身份检查器中将其类从 UIViewController 更改为 NewInsideController:
在此处输入图像描述

将我们的 View(*) 作为视图分配给 NewInsideController:
在此处输入图像描述

现在 IB 中的所有主要操作都已完成。我们需要在 DetailViewController 中创建 NewInsideController 的实例。您可以手动完成,但 Xcode 有一个很好的功能 - 拖放;)
在此处输入图像描述

我将此属性称为 myNewInsideController ,DetailViewController.h 如下所示

#import <UIKit/UIKit.h>
#import "NewInsideController.h"

@interface DetailViewController : UIViewController

@property (strong, nonatomic) id detailItem;
@property (strong, nonatomic) IBOutlet NewInsideController *myNewInsideController;

@property (strong, nonatomic) IBOutlet UILabel *detailDescriptionLabel;
@end

: ,现在我们的 NewInsideController 已准备好工作并管理其视图。让我们向该视图添加按钮和操作以验证这一点:
在此处输入图像描述

在 NewInsideController 中的 IBAction 中编写一些代码。

- (IBAction)insideButtonClick:(id)sender {
    float rPart = arc4random()%100/100.0f;
    float gPart = arc4random()%100/100.0f;    
    self.view.backgroundColor = [UIColor colorWithRed:rPart green:gPart blue:0.5f alpha:1.0f];
}

运行程序。

Let's consider following example based on Master-Detailed Application for iPhone only.

So, add new view controller in newly created project in Xcode:
enter image description here

I called it NewInsideViewController. Create it without xib:
enter image description here

Open DetailViewController.xib. Drag View Controller and View(*) objects from library to Objects area like this (I changed view's color to LightGray):
enter image description here

Choose this View Controller and change its Class from UIViewController to NewInsideController at the Identity Inspector:
enter image description here

Assign our View(*) to NewInsideController as a view:
enter image description here

Now all main actions in IB finished. We need to create instance of NewInsideController in our DetailViewController. You can do it by hand, but Xcode has a nice feature - drag-n-drop ;)
enter image description here

I called this property as myNewInsideController and DetailViewController.h looks like this:

#import <UIKit/UIKit.h>
#import "NewInsideController.h"

@interface DetailViewController : UIViewController

@property (strong, nonatomic) id detailItem;
@property (strong, nonatomic) IBOutlet NewInsideController *myNewInsideController;

@property (strong, nonatomic) IBOutlet UILabel *detailDescriptionLabel;
@end

Well, now our NewInsideController ready to work and manage its view. Let's add button and action to that view in order to verify this:
enter image description here

Write some code in IBAction in NewInsideController.

- (IBAction)insideButtonClick:(id)sender {
    float rPart = arc4random()%100/100.0f;
    float gPart = arc4random()%100/100.0f;    
    self.view.backgroundColor = [UIColor colorWithRed:rPart green:gPart blue:0.5f alpha:1.0f];
}

Run program.

喜爱纠缠 2025-01-10 13:35:19

如果我清楚地理解这个问题:

  1. 您有一个来自 XIB 的父视图和控制器。
  2. 您已将子视图放入父视图中。
  3. 您希望放置到父视图中的每个子视图都有自己的(自定义)控制器,但您不知道如何将视图控制器添加到层次结构中(XCode 不允许您将视图控制器拖到视图的画布中)。

因此,简单地回答这个问题:假设您的项目中有一些自定义 UIViewController(每个视图控制器由 .h 和 .m 组成)。请记住,如果您将它们放在父级上下文中,它们不应该有自己的 XIB(您不能将 XIB 嵌套在 IB 中)。这里需要注意的是,您应该只将界面“布局”在一个位置。如果您想为每个子视图都有一个 XIB,这不是正确的方法。然而,您可以(不应该)做的是拥有多个自定义视图控制器,每个视图控制器都连接到位于父视图中的自己的视图,并且您可以将子视图控制器的出口设置为这个父视图。唷,有点乱。您需要注意的另一件事是,您的父视图控制器需要对其每个子视图控制器的引用,以便您能够以编程方式访问这些子控制器及其出口,因此对于每个子视图控制器添加视图控制器时,您还需要在父视图控制器中添加一个指向每个子视图控制器的 IBOutlet:

 ParentViewController.h
 @property (nonatomic, weak) IBOutlet CustomUIViewController *firstCustomController;

然后例如在第一个自定义子视图/控制器的视图上设置背景颜色:

ParentViewController.m
[[[self firstCustomController] view] setBackgroundColor:[UIColor whiteColor]];

打开您的父视图控制器IB。如果您查看可用对象的抽屉,您将找到一个通用 UIViewController 对象。将其拖到您的父视图控制器中(不是拖到它的视图画布上,而是拖到父 UIViewController 对象本身中,如 IB 构建器的左列所示)。选择您添加的通用视图控制器并将其类设置为您所需的 UIViewController 子类。现在,当您的 XIB 加载时,它将实例化您的自定义视图控制器的实例以及您添加到其画布中的任何内容。

最后,将通用 UIView 拖到画布上,将其放置在现有控制器的视图中(您的屏幕截图已显示此操作已完成)。右键单击您的自定义视图控制器,并将其“视图”出口连接到您添加的视图。

现在,当您运行时,您的自定义视图控制器在屏幕上有一个视图,它是您的自定义控制器子类的视图,并且您没有在代码中执行任何操作。

现在您已经完成了,请考虑它是否是最佳选择:嵌套视图控制器构建起来很混乱(正如您所见),并且不一定是一个好的设计决策:http://blog.carbon Five.com/2011/03/09/abusing-uiviewcontrollers/

虽然iOS5确实支持嵌套视图控制器,但我个人会避免使用它们。我重视一个最佳实践:一个屏幕 = 一个视图控制器。

在此处输入图像描述

If I understand the question clearly:

  1. You have a parent view and controller, coming from a XIB.
  2. You have placed subviews into the parent view.
  3. You're wanting each subview placed into the parent view to have it's own (custom) controller, but you don't know how to add view controller's to your hierarchy (XCode will not let you drag view controllers into a view's canvas).

So, to answer the question succinctly: Let's assume you have a handful of custom UIViewController's in your project (each view controller consisting of a .h and a .m). Remember that you if you are laying these out in the context of the parent, they shouldn't have their own XIBs (you cannot nest XIBs in IB). What is important to note here is that you should only "layout" the interface in one location. If you want to have a XIB for each subview, this is not the correct approach. What you can (not should) do, however, is have several custom viewControllers, each connected to it's own view sitting within your parentView, and you can have the outlets of your sub view controller's set to objects in this parentView. Phew, kinda messy. The other thing you'd need to be aware of is that your parent view controller would need a reference to each of it's sub view controllers in order for you to be able to access those sub-controllers and their outlets programmatically, so for each sub view controller you add, you would also need to add an IBOutlet in your parent view controller pointing to each subviewController:

 ParentViewController.h
 @property (nonatomic, weak) IBOutlet CustomUIViewController *firstCustomController;

And then for example to set the background color on the view of your first custom subview/controller:

ParentViewController.m
[[[self firstCustomController] view] setBackgroundColor:[UIColor whiteColor]];

Open up your parent view controller in IB. If you look in your drawer of available objects, you'll find a generic UIViewController object. Drag this into your parent view controller (NOT onto it's views canvas, rather into the parent UIViewController object itself as seen in the left-column of IB builder). Select the generic view controller you've added and set it's class to your desired UIViewController subclass. Now, when your XIB loads, it will instantiate an instance of your custom view controller along with whatever you've added to it's canvas.

Finally, drag a generic UIView onto your canvas, placing it inside your existing controller's view (your screenshot already shows this as done). Right-click your custom view controller, and connect it's 'view' outlet to the view you added.

Now when you run, your custom view controller has a view that is on the screen that is the view of your custom controller subclass, and you didn't do any of it in code.

So now that you've done it, consider whether or not it is the best choice: Nested view controllers are messy to build (as you've seen) and aren't necessarily a good design decision: http://blog.carbonfive.com/2011/03/09/abusing-uiviewcontrollers/

Although iOS5 does support nested view controllers, personally I'd avoid using them. I value a best practice dictating one screen = one view controller.

enter image description here

围归者 2025-01-10 13:35:19

您永远不会想要获取已经在某个视图控制器控制下的视图,并使它们成为另一个视图控制器视图的子视图。

视图控制器是 MVC 设计模式中的 C 部分 - 它们负责控制视图(及其子视图)。您不能获取由控制器管理的视图,并将其作为不同控制器视图的子视图 - 如果您这样做,谁负责管理该视图就会变得模糊。

尽管这种“坚持”在技术上是可能的,但它会创建难以理解、难以维护的代码,最重要的是,由于谁负责管理视图的不明确以及由于以下事实,会导致错误: Apple 的视图/控制器框架不支持此功能。

例如:如果设备内存不足,Apple 会确保卸载当前未显示的视图。 Apple 依靠视图控制器层次结构来了解何时可以卸载视图。如果将视图控制器的视图粘贴到另一个视图控制器的视图中,则即使该视图不可见,也很可能永远不会被卸载。

不要破坏视图控制器层次结构,而是执行以下操作之一:

  1. 只需通常将子视图添加到视图中,无论是在界面生成器中,还是在 -viewDidLoad: 中以编程方式添加它们,或者(罕见)覆盖 <代码>-loadView。
  2. 使用视图控制器包含,可以使用 Apple 的现成控制器(UINavigationController、UISplitViewController 等),也可以使用您自己的容器视图控制器(iOS>5)。
  3. 以模态方式显示视图控制器。

破坏视图控制器层次结构的坏主意确实很常见,并且经常在第三方中看到,可能是因为它是如此简单且看似简单。不幸的是,这会导致上述错误:-(

我真的建议每个参与此线程和评论的人阅读 Apple 的 查看控制器编程指南,并观看 WWDC 2011 “查看控制器遏制”视频。

You never, EVER, want to take views which are already under the control of a certain view controller, and make them subviews of another view controller's view.

View Controllers are the C part in the MVC design pattern - They are in charge of controlling a view (and its subviews). You can't take a view which is being managed by a controller, and stick it as a subview of a different controller's view - If you do that, it becomes ambigous who is responsible to manage this view.

Even though this "sticking" might be possible technically, it creates code which is hard to understand, hard to maintain, and most importantly - will cause bugs due to the unclarity of who is responsible to manage the view, and due to the fact that Apple's View/Controller framework doesn't support this.

For example: If the device is low on memory, Apple makes sure to unload views which are not currently displayed. Apple relies on the view controllers hierarchy to know when it can unload views. If you stick the view controller's view in another view controller's view, it's very likely that the view will never be unloaded even if it isn't visible.

Instead of breaking the view controller hierarchy, do one of the following:

  1. Just add subviews to your view normally, either in interface builder, or in -viewDidLoad: to add them programatically, or (rarer) override -loadView.
  2. Use view controller containment, either with Apple's ready-made ones (UINavigationController,UISplitViewController etc.) or with your own container view controllers (iOS>5).
  3. Display view controllers modally.

The bad idea of breaking a view controller hierarchy is indeed very common and often seen in 3rd parties, probably because it's so easy and seemingly straightforward. Unfortunately this causes the aforementioned bugs :-(

I really recommend to everyone participating in this thread and comments to read Apple's View Controller Programming Guide, and watch WWDC 2011 "View Controller Containment" video.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文