在其他视图中调用时,使用 Interface Builder 创建的自定义视图不会呈现
Custom view created with Interface Builder does not render when called in other views
我有一个主要的 xib window,我按照以下步骤创建了一个自定义视图:
- 创建一个继承自
NSView
的新 class。
MyView.h
:
#import <Cocoa/Cocoa.h>
IB_DESIGNABLE
@interface MyView : NSTableCellView
@end
MyView.m
:
#import "MyView.h"
@implementation MyView
- (void)awakeFromNib {
NSLog(@"Post view awaking from nib.");
}
@end
- 创建一个新的xib,并将根视图的class设置为上面创建的class。并在那个 xib 中进行设计。
- 设置从 xib 到 class 的出口。
并且我尝试按照以下步骤在主 window 中使用此自定义视图:
- 将自定义视图拖到主 window 的 xib。
- 将该自定义视图的 class 设置为上面创建的 class。
但没有渲染。从日志中,我可以看到执行了自定义视图 class 中 awakeFromNib
中的代码。当我将 class 设置为 IB_DESIGNABLE
时,主 window 的 xib 中的视图变为空,与我设计的不同。
我尝试将自定义视图的 xib 的文件所有者设置为自定义 class,但没有任何改变。
我想问题是,自定义视图的 xib 文件实际上没有加载。当我用谷歌搜索时,似乎很少有关于这个确切主题的参考。那么,我应该如何真正实现这个目标呢?即在 IB 中设计一个视图,在 class 中实现它的方法,将这两者关联起来,并像系统视图一样公开它以供其他 xibs 使用?
更新:
我找到了一个教程并意识到我缺少什么(构建时正确渲染视图)。我必须从 xib 中的视图添加一个出口到视图 class:
@property (nonatomic, strong) IBOutlet NSView *view;
,然后在(id)initWithCoder:(NSCoder *)coder
方法中加载。
[[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self topLevelObjects:nil];
[self addSubview:self.view];
但是视图仍然不会在界面生成器中呈现。
您没有提供任何代码,但这里有一些完整性检查:
您是否正确指定了笔尖名称?在 iOS 中,它对大写敏感,但我认为它不适合你。
检查包装,笔尖真的在吗?确保它是您正在构建的目标的一部分。
也可能是框架问题。请确保您的自动调整大小参数设置正确并且所有内容都在框架内。
您可以做的另一项检查是将您的 IBOutlets 设置为您感兴趣的 UIView(或其他)的实际框架。然后在 awakeFromNib 中,您可以确保它们的框架存在,或者它们根本就存在。
您的猜测是正确的:没有加载 xib。 nib 加载程序不知道您的自定义视图的 nib。 nib 框架不提供定义该连接的工具,因此您需要编写代码来加载 xib。
这就是我要做的。添加 contentView
属性 到您的自定义视图:
@interface MyView ()
@property (nonatomic, strong, readwrite) IBOutlet NSView *contentView;
@end
在自定义视图的 nib 中,将根视图的自定义 class 设置回 NSView
并断开所有(不再有效的)出口连接。将文件所有者的自定义 class 设置为您的自定义 class 名称(例如 MyView
)。将根视图连接到文件所有者的 contentView
出口,并将文件所有者的所有其他出口连接到笔尖中的适当对象。
然后在自定义视图 subclass 中实现 awakeFromNib
以加载 nib 并将内容视图添加为子视图:
@implementation MyView {
BOOL hasLoadedOwnNib: 1;
}
- (void)awakeFromNib {
[super awakeFromNib];
[self loadOwnNibIfNeeded];
}
- (void)loadOwnNibIfNeeded {
if (hasLoadedOwnNib) {
return;
}
hasLoadedOwnNib = YES;
[[NSBundle bundleForClass:self.class] loadNibNamed:NSStringFromClass(self.class) owner:self topLevelObjects:nil];
self.contentView.frame = self.bounds;
self.contentView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
[self addSubview:self.contentView];
}
@end
请注意,您必须小心不要允许无限递归。当您的应用程序加载主 window 的 nib 时,它将创建 MyView
的实例并(最终)发送它 awakeFromNib
。然后,在 awakeFromNib
中,MyView
加载它自己的 nib,它是文件的所有者。 nib 加载程序将 awakeFromNib
发送给文件所有者,这将在您已经在 -[MyView awakeFromNib]
中时发生。如果你不检查这个,你会由于无限递归而导致堆栈溢出。
我有一个主要的 xib window,我按照以下步骤创建了一个自定义视图:
- 创建一个继承自
NSView
的新 class。
MyView.h
:
#import <Cocoa/Cocoa.h>
IB_DESIGNABLE
@interface MyView : NSTableCellView
@end
MyView.m
:
#import "MyView.h"
@implementation MyView
- (void)awakeFromNib {
NSLog(@"Post view awaking from nib.");
}
@end
- 创建一个新的xib,并将根视图的class设置为上面创建的class。并在那个 xib 中进行设计。
- 设置从 xib 到 class 的出口。
并且我尝试按照以下步骤在主 window 中使用此自定义视图:
- 将自定义视图拖到主 window 的 xib。
- 将该自定义视图的 class 设置为上面创建的 class。
但没有渲染。从日志中,我可以看到执行了自定义视图 class 中 awakeFromNib
中的代码。当我将 class 设置为 IB_DESIGNABLE
时,主 window 的 xib 中的视图变为空,与我设计的不同。
我尝试将自定义视图的 xib 的文件所有者设置为自定义 class,但没有任何改变。
我想问题是,自定义视图的 xib 文件实际上没有加载。当我用谷歌搜索时,似乎很少有关于这个确切主题的参考。那么,我应该如何真正实现这个目标呢?即在 IB 中设计一个视图,在 class 中实现它的方法,将这两者关联起来,并像系统视图一样公开它以供其他 xibs 使用?
更新:
我找到了一个教程并意识到我缺少什么(构建时正确渲染视图)。我必须从 xib 中的视图添加一个出口到视图 class:
@property (nonatomic, strong) IBOutlet NSView *view;
,然后在(id)initWithCoder:(NSCoder *)coder
方法中加载。
[[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self topLevelObjects:nil];
[self addSubview:self.view];
但是视图仍然不会在界面生成器中呈现。
您没有提供任何代码,但这里有一些完整性检查:
您是否正确指定了笔尖名称?在 iOS 中,它对大写敏感,但我认为它不适合你。
检查包装,笔尖真的在吗?确保它是您正在构建的目标的一部分。
也可能是框架问题。请确保您的自动调整大小参数设置正确并且所有内容都在框架内。
您可以做的另一项检查是将您的 IBOutlets 设置为您感兴趣的 UIView(或其他)的实际框架。然后在 awakeFromNib 中,您可以确保它们的框架存在,或者它们根本就存在。
您的猜测是正确的:没有加载 xib。 nib 加载程序不知道您的自定义视图的 nib。 nib 框架不提供定义该连接的工具,因此您需要编写代码来加载 xib。
这就是我要做的。添加 contentView
属性 到您的自定义视图:
@interface MyView ()
@property (nonatomic, strong, readwrite) IBOutlet NSView *contentView;
@end
在自定义视图的 nib 中,将根视图的自定义 class 设置回 NSView
并断开所有(不再有效的)出口连接。将文件所有者的自定义 class 设置为您的自定义 class 名称(例如 MyView
)。将根视图连接到文件所有者的 contentView
出口,并将文件所有者的所有其他出口连接到笔尖中的适当对象。
然后在自定义视图 subclass 中实现 awakeFromNib
以加载 nib 并将内容视图添加为子视图:
@implementation MyView {
BOOL hasLoadedOwnNib: 1;
}
- (void)awakeFromNib {
[super awakeFromNib];
[self loadOwnNibIfNeeded];
}
- (void)loadOwnNibIfNeeded {
if (hasLoadedOwnNib) {
return;
}
hasLoadedOwnNib = YES;
[[NSBundle bundleForClass:self.class] loadNibNamed:NSStringFromClass(self.class) owner:self topLevelObjects:nil];
self.contentView.frame = self.bounds;
self.contentView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
[self addSubview:self.contentView];
}
@end
请注意,您必须小心不要允许无限递归。当您的应用程序加载主 window 的 nib 时,它将创建 MyView
的实例并(最终)发送它 awakeFromNib
。然后,在 awakeFromNib
中,MyView
加载它自己的 nib,它是文件的所有者。 nib 加载程序将 awakeFromNib
发送给文件所有者,这将在您已经在 -[MyView awakeFromNib]
中时发生。如果你不检查这个,你会由于无限递归而导致堆栈溢出。