如何在 Interface Builder 中获取视图以在另一个笔尖中加载自定义视图?
我正在制作一个自定义小部件,我想在多个笔尖中使用它。因此,我创建了一个新视图 nib Screen3,添加了一些按钮,现在想要我的 UIAwesomeSauce 小部件。
如果我只是添加一个视图,然后更改类标识,它不会从 UIAwesomeSauce 笔尖获取子元素。如果我去图书馆并切换到课程,也会发生同样的情况。似乎只有 UIViewController 具有“从笔尖加载”字段,这会很漂亮。
我知道我可以从代码加载 UIAwesomeSauce 笔尖,获取顶级对象,然后手动放置它。但 IB 的目的是让您不必将内容放入代码中。如果我能让 UIAwesomeSauce 显示在库列表本身中,那就更好了。
已解决 - 由 Nimrod - 阅读解释和代码
无论如何,dood,这太棒了。我现在可以为愚蠢的很棒的东西制作自己的小部件类。将 UI nib 的 FileOwner 设为您的类,并在其中包含一个包含所有内容的普通 UIView。 (小部件笔尖中的单个视图不能是类本身,否则您会在 initWithCoder 中递归。)然后在要使用它的笔尖中,创建一个普通 UIView 并更改其类。您将无法实际看到该方块内的小部件,但放心吧。
Self 现在是一个空白视图,tMyActualSelf 是您在另一个笔尖中完成工作的单个视图。耶!
- (id)initWithCoder:(NSCoder*)coder
{
if ((self = [super initWithCoder:coder]))
{
UIView *tMyActualSelf = nil;
// Initialization code
NSArray *tNibItems = [[NSBundle mainBundle] loadNibNamed:@"UIAwesomeSauce" owner:self options:nil];
for (id object in tNibItems)
{
if ([object isKindOfClass:[UIView class]])
tMyActualSelf = (UIView *)[object retain];
}
if( tMyActualSelf )
{
tMyActualSelf.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
[self addSubview:tMyActualSelf];
}
}
return self;
}
I am making a custom widget that I would like to use in multiple nibs. So I make a new view nib Screen3, add some buttons, and now want my UIAwesomeSauce widget.
If I just add a view and then change the Class Identity, it doesn't get the subelements from the UIAwesomeSauce nib. Same thing if I go to the Library and switch to Classes. It seems only a UIViewController has the field for "Load from nib", which would be beautiful.
I know I can load the UIAwesomeSauce nib from code, get the top level objects, and place it by hand. But the point of IB is so you don't have to place things in code. Even better would be if I could get UIAwesomeSauce to show up in the Library list itself.
SOLVED - by Nimrod - READ ON FOR EXPLANATION AND CODE
Anyway, dood, that is great. I can make my own widget classes now for goofy Awesome stuff. Make the FileOwner of your UI nib your class, and in it just have a normal UIView with all your stuff. (The single view in the widget's nib can't be the class itself, or you get recursive in initWithCoder.) Then in the nib you want to use it, make a vanilla UIView and change its class. You won't be able to actually see the widget inside that square, but deal.
Self is now a blank view, and tMyActualSelf is the single view that you did the work in in the other nib. Yay!
- (id)initWithCoder:(NSCoder*)coder
{
if ((self = [super initWithCoder:coder]))
{
UIView *tMyActualSelf = nil;
// Initialization code
NSArray *tNibItems = [[NSBundle mainBundle] loadNibNamed:@"UIAwesomeSauce" owner:self options:nil];
for (id object in tNibItems)
{
if ([object isKindOfClass:[UIView class]])
tMyActualSelf = (UIView *)[object retain];
}
if( tMyActualSelf )
{
tMyActualSelf.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
[self addSubview:tMyActualSelf];
}
}
return self;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
当谈到 UIViewController 是唯一可以指定笔尖加载的东西时,我感到你的痛苦,但我认为这是因为必须有一个文件的所有者是一个控制器,或类似的东西,尽管我不确定为什么UIView 不能是文件的所有者。
我认为您可以将内容放在库中的“自定义对象”下,但我认为您只能将 UIView 放入其中,并将该类设置为 UIView 的自定义子类。我实际上研究过尝试扩展界面构建器,看起来你可以为 OS X 的东西做到这一点,但不能为 iPhone 的东西做到这一点。它涉及在界面构建器中为新小部件编译代码,以告诉它如何在 IB 中绘制小部件。我认为实际上有一个 OS X 模板可以实现这一点。
我想我可能会做的是在包含所有子视图的 nib 文件中创建一个主视图,然后在 initWithCoder: 在 UIAwesomeSauce 中打开 nib 文件,加载主视图,然后将其放在 self 中,以便您在 UIAwesomeSauce 视图和子视图(或子子视图,视情况而定)之间有一个“不必要的”视图。我不确定这效率有多低,但在搞乱一些东西时,看起来像 UIWebView 这样的视图似乎有这些看似不必要的中间观点之一(IIRC)。
如果您想出更好的解决方案请告诉我,因为我也想知道。
编辑
现在我看看它,我认为 UIView 可以是文件的所有者,你只是不能在 IB 中设置它。基本上你会在 UIView 子类中调用类似这样的笔尖加载:
[bundle loadNibNamed:@"UISpecialSauce" Owner:self options:...]
我认为如果你在 UISpecialSauce 或其他什么中创建出口,那么它们应该被正确分配,因为业主:本人。
I feel your pain when it comes to the UIViewController being the only thing you can specify a nib load with, but I think it's because there has to be a File's Owner that's a controller, or something like that, though I'm not sure why a UIView can't be a File's Owner.
I think you can put things in the library under Custom Objects but I think you'd be limited to putting a UIView in there with the class just set to a custom subclass of UIView. I actually looked into trying to extend interface builder and it looks like you can do it for OS X stuff, but not for iPhone stuff. It involves compiling code for the new widget in interface builder to tell it how to draw the widget just within IB. I think there's actually an OS X template for this.
I think what I'd probably do is create a main view in a nib file that contains all the subviews, then in initWithCoder: in the UIAwesomeSauce thing open the nib file, load the main view, and just place it inside self so that you have an "unnecessary" view between the UIAwesomeSauce view and the subviews (or sub subviews as the case would be.) I'm not sure how inefficient that is, but in messing with some stuff it looks like some views like UIWebView seem to have one of these seemingly unnecssary intermediate views (IIRC).
If you come up with a better solution please tell me because I'd like to know too.
EDIT
Now that I look at it, I think the UIView CAN be the file's owner, you just can't set it up in IB. Basically you'd call the nib load something like this in the UIView subclass:
[bundle loadNibNamed:@"UISpecialSauce" owner:self options:...]
I think if you create outlets in UISpecialSauce or whatever then they should be assigned correctly because of the owner:self.
有一个 cocoapod 可能实际上可以帮助解决这个问题:
https://github.com/mobilejazz/NibWrapper
它提供了一个包装视图,可以从另一个视图加载子视图笔尖。您可以通过运行时属性在接口构建器内指定该 NIB 的名称。
Theres a cocoapod that might actually help with that:
https://github.com/mobilejazz/NibWrapper
It provides a wrapper view that loads a child view from another NIB. You can specify the name of that NIB inside interface builder via a runtime attribute.