使用Storyboard创建自定义视图

96
在复杂的屏幕(视图控制器)中,我过去通常将整个内容分成更小的部分(我称之为小部件)。这些小部件基本上由一个 MyWidget.h 和一个 MyWidget.m 文件以及一个 MyWidget.xib 文件组成,其中根元素是一个 UIView,而 MyWidget 类是 UIView 的文件所有者。在这个小部件的初始化中,我会执行一个 loadNibNamed
然后在我的视图控制器中,我会执行 [[MyWidget alloc] init],并将其作为子视图添加到 View Controller 的主视图中。到目前为止,这一点运行得很完美。
我现在想知道如何在故事板中做同样的事情,因为我不能真的开始拖动一个 UIView 到某个地方,我总是不得不从一个 UIViewController 开始,而我不想要这个。
如果没有可能使用 Storyboard 进行此操作,我是否可以简单地按照旧方法进行操作,即使用 Storyboard 来定义我的主要屏幕和 Segue,而使用单独的 .xib 文件来定义自定义视图?

您是否希望单独为视图控制器创建 xib 而不是在故事板中创建? - tipycalFlow
@aryaxt:我正在使用Storyboard和xib的混合方式。Storyboard用于主屏幕,而对于复杂视图或小部件,我只使用带有UIView作为根视图的xib。因此,这并不是对我的原始问题的答案(通过使用Storyboard),而基本上是在做我之前已经做过的事情。 - znq
现在的做法就是使用容器视图,非常简单。https://dev59.com/KGAg5IYBdhLWcg3wm7_6#23403979 - Fattie
3个回答

189

将小部件/视图放在一个单独的.xib文件中是可行的,如果您可能想要从多个视图控制器引用相同的视图,则更为合适。

然而,有时候您确实希望在同一个故事板中看到额外的视图/小部件,并且这是可能的。 下面是具体的操作步骤:

  1. 在IB中选择您的视图控制器(单击视图下方的黑色条),然后将UIView从Object Library拖到黑色条中:

    enter image description here

  2. 当视图位于黑色条中时,它会像IB中的任何其他视图一样被实例化,但直到您在代码中添加它到视图层次结构中为止。根据需要更改视图的类以与自己的子类匹配:

    enter image description here

  3. 您可以像连接其他视图一样来连接它到视图控制器:enter image description here

  4. 添加的视图将显示在文档大纲中,并且您也可以在那里连接操作和引用:

    enter image description here


现在,仍然存在的问题是无论您尝试点击或双击多少次,都无法实际看到视图,这将使将其放在同一个故事板中的整个目的落空。幸运的是我知道两种解决方法。

第一种解决方法是将视图从黑色条中拖回到视图控制器的视图中进行编辑,完成后再将其拖回到黑色条中。虽然有些麻烦,但很可靠。

另一种解决方法更为微妙,但我更喜欢它,因为它允许我同时查看所有视图:

  1. 从Object Library将UITableView拖入新添加的视图中。

  2. 然后将UITableViewCell拖入该UITableView中。

    这里输入图像描述

  3. 完成上述步骤后,你的视图就会神奇地出现在侧边,但是你会发现有一个你不想要的UITableView。你可以将其大小调整为0x0,或者删除它,你的UIView(通常)仍然可见。

  4. 有时,在IB中次级视图会再次隐藏。如果您已删除UITableView,则可以重复上述步骤,如果UITableView仍位于层次结构中,则只需单击UITableViewCell即可再次显示视图。

第二种方法适用于UIView,但对UIToolbar效果不太好,对于UIButtons则不可能。因此,当您需要包含许多不同的子视图时,我发现最干净的解决方案是将单个次级UIView附加到您的视图控制器作为容器,该容器永远不会显示,将所有次级视图放入其中,并使用UITableViewCell技巧使所有内容都可见。我将我的虚拟UITableView大小调整为0x0以使其变为不可见。以下是它们全部放在一起的截图:

这里输入图像描述


2
当然,我更喜欢创建一个单独的xib文件。也许在6个月后更新应用程序时,我不会记得所有这些内容。 - Sandy
现在在Xcode 5中无法工作,请查看我的问题链接:https://dev59.com/eXfZa4cB1Zd3GeqPNRrC - Sunil Zalavadiya
@OdedBenDov,您能简要解释一下您的方法吗?我没有理解您关于“将连接器(绘制的线条)悬停在此视图上方”的那行代码。 - Thangavel
正如我之前写的那样,在XCode 5中似乎不起作用。但我的意思是,您可以将连接器从插座拖动到实际组件上。如果您保持按住鼠标按钮,并将光标移动到UIView上方,并在那里逗留一会儿 - 视图将打开,以让您选择其中的组件。 - Oded Ben Dov
7
虽然这是一个非常令人钦佩的历史性答案,但实际上它现在已经完全过时了。苹果公司通过引入“容器视图”来解决了整个问题,这现在是制作应用程序时的中心和基本操作 - 每次都需要使用“容器视图”。谢天谢地,现在非常容易! - Fattie
显示剩余9条评论

11

如果你只是想在故事板外创建你的视图控制器(而不在你的故事板中),那么有一种相当简单的方法可以实现:

1)像往常一样使用它们各自的xib创建您的CustomViewController(在我尝试的代码中为abcdController)。

2)向故事板添加一个UIViewController(或者您的CustomViewController的父类)。

3)将CustomClass设置为CustomViewController,而不是如下所示的UIViewController:

enter image description here

4)最后,在您的viewDidLoad中加载自定义xib,然后完成。

- (void)viewDidLoad
{
    [super viewDidLoad];
    [[NSBundle mainBundle] loadNibNamed:@"abcdController" owner:self options:nil];
    // Do any additional setup after loading the view from its nib.
}

3
谢谢您提供详细的答案,但实际上我不是在寻找自定义视图控制器,而是一个自定义视图(小部件),它会被添加到标准的UIViewController中。所以视图控制器不是问题,但我想知道创建自定义小部件的最佳方法是什么。是A)像之前一样用.xib文件还是B)其他我还不知道的方法 :-) - znq
1
嗯...我想我明白你想要什么了。基本上,你想用同一个控制器处理多个视图,对吧?在这种情况下,我想不到其他方法,除了使用loadNibNamed...XO - tipycalFlow
这个对我解决了问题:https://dev59.com/q2gu5IYBdhLWcg3w0qRK然而,我使用的是loadView而不是viewDidLoad... - Morkrom
1
只是重申一下,现在容器视图已经出现了,这一切(谢天谢地!)都已经过时了。只需单击一个容器视图,一切都完成了。 - Fattie

1
我认为你可以这样做,从Storyboard中获取特定视图控制器的实例,并在其上使用视图。
ex:
MyViewController* myViewController = [[UIStoryboard storyboardWithName:@"Main"  bundle:nil] instantiateViewControllerWithIdentifier:@"myViewController"];
UIView* view = myViewController.view; //Get the view from your StoryBoard.

希望这有所帮助。

谢谢
Vijay


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接