首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >loadNibNamed是如何工作的?UIView插座未使用loadNibNamed初始化

loadNibNamed是如何工作的?UIView插座未使用loadNibNamed初始化
EN

Stack Overflow用户
提问于 2013-12-02 08:01:13
回答 2查看 16K关注 0票数 12

我知道这是相当直截了当的,但经过太多的头发拉扯,我远没有解决问题。

我看过教程,解释如何使用XIB和all创建视图。但他们都没有提到我在这里的情况。

我有一个XIB文件,这是一个定制的UIView子类,没有多少标签和按钮。UIView子类是可重用的,这就是为什么我不能在任何单一的视图控制器中有出口的原因。因此,我将该视图的各个控件(子视图)存储在自定义UIView本身中。这是合乎逻辑的,因为任何视图控制器都不应该拥有此自定义视图的子视图,该视图将包含在每个视图控制器中。

问题是,我不知道如何完全初始化整个UI。

下面是我的UIView子类代码:

代码语言:javascript
复制
@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中使用相同的面向景观的控件。

以下是实施情况:

代码语言:javascript
复制
@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获得相同的对象?也是一个半生不熟的吗?

请帮帮我..。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-04-05 11:47:55

令我困惑的是loadnibnamed丢失xib布局和出口信息的方式。我终于找到了实现这一目标的方法。

以下是工作原理的简要介绍:

1)假设MyCustomView是您的自定义视图类-您将它及其子视图设计为XIB的一部分。您可以通过界面构建器来实现这一点,所以这是不言而喻的。

2)通过Xcode ->文件->新->目标C类添加MyCustomView.h和MyCustomView.m (样板)。

3)接下来,在MyCustomView.xib中设置文件的所有者= MyCustomView (刚刚添加了类名)。不触及大多数视图的自定义类--将其保留为UIView。否则,它将在递归中结束!

4)在MyCustomView.h中,创建几个与MyCustomView.xib中的子视图相对应的出口。

例如:

代码语言:javascript
复制
@property (weak)  IBOutlet UILabel * label1;
@property (weak)  IBOutlet UIButton * button1;

5)去MyCustomView.xib。选择每个子视图(标签,按钮),右键单击,从“新引用出口”拖动到文件所有者。

这将从拖动的位置弹出与子视图类型匹配的插座列表。如果从标签中拖动,它会弹出label1,等等。这表明你所做的一切都是正确的。

另一方面,如果你在任何一步都搞砸了,就不会出现弹出窗口。检查步骤,特别是3和4。

如果不正确执行此步骤,Xcode将欢迎您遵循以下异常:

代码语言:javascript
复制
setValue:forUndefinedKey: this class is not key value coding-compliant for the key

6)在MyCustomView.m中,粘贴/覆盖以下代码:

代码语言:javascript
复制
-(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。

它应该启动&运行没有问题!

票数 19
EN

Stack Overflow用户

发布于 2013-12-02 08:44:11

loadNibNamed不处理框架设置,它只加载内容并使对象对代码可用。必须调用initWithFrame:将新对象插入到窗口的视图继承结构中。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20323393

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档