我知道这很直截了当,但经过太多的牵扯,我离解决方案还差得很远。
我看过解释如何使用 XIB 和所有内容创建 View 的教程。但他们都没有解决我在这里遇到的情况。
我有一个 XIB 文件,它是一个自定义的 UIView 子类,几乎没有标签和按钮。 UIView 子类是可重用的,这就是我不能在任何单个 View Controller 中设置 socket 的原因。因此,我将此 View 的各个控件( subview )存储在我的自定义 UIView 本身中。这是合乎逻辑的,因为任何 View Controller 都不应拥有此自定义 View 的 subview ,该自定义 View 将包含在每个 View Controller 中。
问题是,我不知道如何完全初始化整个 UI。
这是我的 UIView 子类代码:
@interface MCPTGenericView : UIView
+(id)createInstance : (bool) bPortrait;
@property (weak, nonatomic) IBOutlet UIView *topView;
@property (weak, nonatomic) IBOutlet UIView *titleView;
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@property (weak, nonatomic) IBOutlet UIButton *logoButton;
@property (weak, nonatomic) IBOutlet UITextField *searchTextField;
@property (weak, nonatomic) IBOutlet UIButton *menuButton;
@end
稍后,我还计划将同一个 XIB 文件用于此 UIView 的横向,并且我计划在同一个 XIB 中使用具有横向控件的上述 socket 。
下面是实现:
@implementation MCPTGenericView
//@synthesize topView, titleLabel, titleView;
+(id)createInstance : (bool) bPortrait
{
UIView * topLevelView = nil;
MCPTGenericView * instance = [MCPTGenericView new];
NSArray * views = [[NSBundle mainBundle] loadNibNamed:@"MoceptGenericView" owner:instance options:nil];
int baseTag = (bPortrait)?PORTRAIT_VIEW_TAG_OFFSET:LANDSCAPE_VIEW_TAG_OFFSET;
// make sure customView is not nil or the wrong class!
for (UIView * view in views)
{
if (view.tag == baseTag)
{
topLevelView = view;
break;
}
}
instance.topView = (MCPTGenericView *)[topLevelView viewWithTag:baseTag + 1];
instance.searchTextField = (UITextField *)[topLevelView viewWithTag:baseTag + 2];
instance.menuButton = (UIButton *)[topLevelView viewWithTag:baseTag + 3];
instance.logoButton = (UIButton *)[topLevelView viewWithTag:baseTag + 4];
instance.titleView = [topLevelView viewWithTag:baseTag + 5];
instance.titleLabel = (UILabel *)[topLevelView viewWithTag:baseTag + 6];
return instance;
}
-(id)initWithCoder:(NSCoder *)aDecoder
{
if ((self = [super initWithCoder:aDecoder]))
{
[self addSubview:[[[NSBundle mainBundle] loadNibNamed:@"MCPTGenericView" owner:self options:nil] objectAtIndex:0]];
}
return self;
}
-(void)awakeFromNib
{
[super awakeFromNib];
[self addSubview: self.titleView];
[self addSubview:self.topView];
}
- (id) init
{
self = [super init];
if (self)
{
[[NSBundle mainBundle] loadNibNamed:@"MCPTGenericView" owner:self options:nil];
[self addSubview:self.topView];
[self addSubview:self.titleView];
}
return self;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// Initialization code
[[NSBundle mainBundle] loadNibNamed:@"MCPTGenericView" owner:self options:nil];
[self addSubview:self.topView];
[self addSubview:self.titleView];
}
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
@end
有用的东西:
我成功地从我的 View Controller 调用了 initWithFrame:frame
。这样,我可以看到所有控件都已正确初始化。但是,如果我已经绘制了 XIB,为什么还要提供框架呢? loadNibNamed 不应该处理框架设置和布局内容,因为这是 XIB 的预期用途吗?
我也对 loadNibNamed 需要所有者对象的方式感到困惑。为什么我们已经需要一个对象来从 XIB 获取相同的对象?那也是半生不熟的?
请帮忙...
最佳答案
令我困惑的是 loadnibnamed
丢失 xib 布局和导出信息的方式。我终于找到了实现它的方法。
这里是对有效方法的回顾:
1) 假设 MyCustomView 是您的自定义 View 类 - 您将其及其 subview 设计为 XIB 的一部分。您可以通过界面生成器执行此操作,不言自明。
2) 通过 Xcode -> File -> New -> Objective C Class 添加 MyCustomView.h 和 MyCustomView.m(样板)。
3) 接下来,在 MyCustomView.xib 中,设置 File's Owner = MyCustomView(刚刚添加的类名)。 不要触及最顶层的 View 自定义类 - 将其保留为 UIView。否则它会以递归结束!!!
4) 在 MyCustomView.h 中,创建几个与 MyCustomView.xib 中的 subview 对应的导出。
如:
@property (weak) IBOutlet UILabel * label1;
@property (weak) IBOutlet UIButton * button1;
5) 转到 MyCustomView.xib。选择每个 subview (标签、按钮),单击鼠标右键,从“New Referencing Outlet”拖动并将其向上拖动到 File's Owner。
这将弹出一个与您拖动的 subview 类型相匹配的 socket 列表。如果你从一个label拖过来,就会弹出label1,以此类推。这表明您到这一步所做的一切都是正确的。
另一方面,如果您在任何步骤中搞砸了,则不会出现弹出窗口。检查步骤,尤其是 3 和 4。
如果您没有正确执行此步骤,Xcode 将欢迎您出现以下异常:
setValue:forUndefinedKey: this class is not key value coding-compliant for the key
6) 在您的 MyCustomView.m 中,粘贴/覆盖以下代码:
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
NSString * nibName = @"MyCustomView";
[[[NSBundle mainBundle] loadNibNamed:nibName owner:self options:nil] firstObject];
[self addSubview:self.labelContinentName];
}
return self;
}
此步骤至关重要 - 它将您的 socket 值(label1、button1)从 nil 设置为有形 subview ,最重要的是,根据您在 MyCustomView.xib 中设置的内容设置它们的框架。
7) 在您的 Storyboard文件中,添加 MyCustomView 类型的 View - 就像任何其他 View 一样:
- 在您的 View Controller 主视图矩形中拖动一个 UIView
- 选择新添加的 View
- 在 Utilities -> Identity Inspector 中,设置自定义类值 = MyCustomView。
它应该可以正常运行!
关于ios - loadNibNamed 如何工作? UIView socket 未使用 loadNibNamed 进行初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20323393/