我知道这很简单,但经过太多的努力,我离解决方案还差得很远。
我看过一些教程,解释了如何使用XIB创建视图等等。但他们都没有解决我在这里遇到的情况。
我有一个XIB文件,一个自定义的UIView子类,几乎没有标签和按钮。UIView子类是可重用的,这就是我不能在任何一个View控制器中有出口的原因。因此,我将此视图的各个控件(子视图)存储在自定义UIView本身中。这是合乎逻辑的,因为任何视图控制器都不应该拥有将包含在每个视图控制器中的此自定义视图的子视图。
问题是,我不知道如何完全初始化整个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中使用具有横向控件的上述相同出口。
这里是实现:
@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
有效的东西:
我成功地从视图控制器调用了initWithFrame:frame
。这样,我可以看到所有控件都已正确初始化。但是,如果我已经画了一个XIB,为什么还要提供一个框架呢?loadNibNamed不应该处理帧设置和布局的事情吗?因为这是XIB的预期用途吗?
我还对loadNibNamed需要所有者对象的方式感到困惑。为什么我们已经需要一个对象来从XIB获得相同的对象?那也是一个半生不熟的?
请帮忙。。。
让我困惑的是loadnibnamed
失去xib布局的方式;网点信息。我终于找到了实现它的方法
以下是工作原理的概述:
1) 假设MyCustomView是您的自定义视图类,您将其及其子视图设计为XIB的一部分。您可以通过接口构建器来实现这一点,因此不言自明。
2) 通过Xcode->File->New->Objective C Class添加MyCustomView.h和MyCustomView.m(样板文件)。
3) 接下来,在MyCustomView.xib中,将File的Owner设置为MyCustomView(刚刚添加的类名)不要触摸View的自定义类的顶部-将其保留为UIView。否则它将以递归结束
4) 在MyCustomView.h中,创建几个与MyCustomView.xib.中的子视图相对应的出口
例如:
@property (weak) IBOutlet UILabel * label1;
@property (weak) IBOutlet UIButton * button1;
5) 转到MyCustomView.xib。选择每个子视图(标签、按钮),右键单击,从"新引用出口"拖动,并将其向上拖动到文件的所有者。
这将弹出一个与您拖动的子视图类型匹配的出口列表。如果你从标签中拖动,它会弹出标签1,依此类推。这表明你在这一步之前所做的一切都是正确的。
另一方面,如果你在任何一步都搞砸了,不会出现弹出窗口。检查步骤,尤其是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;
}
这一步至关重要-它将您的出口值(label1,button1)从零设置为有形子视图,最重要的是,根据您在MyCustomView.xib中设置的内容设置它们的框架。
7) 在你的故事板文件中,添加MyCustomView类型的视图-就像任何其他视图一样:
- 在视图控制器主视图矩形中拖动UIView
- 选择新添加的视图
- 在实用程序->标识检查器中,将自定义类值设置为MyCustomView
它应该是up&跑步没问题!
loadNibNamed
不处理帧设置,它只加载内容并使对象可用于代码。必须调用initWithFrame:
才能将新对象插入到窗口的视图层次结构中。