在自包含的自定义UIView子类中使用.xib文件进行原型设计

时间:2015-01-07 18:50:00

标签: ios objective-c uiview uiviewcontroller xib

根据我的经验,最强大的view / viewcontroller实现直接在UIView子类(initWithFrame:layoutSubviews)中完成所有元素创建和布局,而不是使用.xib文件。虽然可以使用.xib文件来获得相同的结果,但复杂性和维护似乎并不值得。我最近开始研究自定义视图控制器和UIView子类,我正在使用ParseUI框架中的PFLogInViewController作为参考来创建我需要的'.xib-free'健壮性。

我的自定义UIView子类(我将其称为NumPadView作为示例)负责布置按钮,标签和其他UI元素,而我的自定义UIViewController子类(我将称之为NumPadViewController作为示例)负责创建NumPadView实例并将目标操作添加到其所有按钮,然后实现这些操作。以下是NumPadView的示例界面:

//
//  NumPadView.h

#import <UIKit/UIKit.h>

@interface NumPadView : UIScrollView
@property (strong, nonatomic, readonly) UIButton *button1;
@property (strong, nonatomic, readonly) UIButton *button2;
@property (strong, nonatomic, readonly) UIButton *button3;
@property (strong, nonatomic, readonly) UIButton *button4;
@property (strong, nonatomic, readonly) UIButton *button5;
@property (strong, nonatomic, readonly) UIButton *button6;
@property (strong, nonatomic, readonly) UIButton *button7;
@property (strong, nonatomic, readonly) UIButton *button8;
@property (strong, nonatomic, readonly) UIButton *button9;
@property (strong, nonatomic, readonly) UIButton *button0;
- (instancetype)init;
@end

使用此界面,NumPadViewController(具有_numPadView属性)可以执行以下操作:

self.view = _numPadView;
[_numPadView.button0 addTarget:self selector:@selector(button0Pressed) forControlEvents:UIControlEventTouchUpInside];

现在,来回答我的问题。最终,所有NumPadView布局都将在代码中完成,类​​似于以下内容:

//
//  NumPadView.m

#import "NumPadView.h"

@interface NumPadView ()
@property (strong, nonatomic, readwrite) UIButton *button1;
@property (strong, nonatomic, readwrite) UIButton *button2;
@property (strong, nonatomic, readwrite) UIButton *button3;
@property (strong, nonatomic, readwrite) UIButton *button4;
@property (strong, nonatomic, readwrite) UIButton *button5;
@property (strong, nonatomic, readwrite) UIButton *button6;
@property (strong, nonatomic, readwrite) UIButton *button7;
@property (strong, nonatomic, readwrite) UIButton *button8;
@property (strong, nonatomic, readwrite) UIButton *button9;
@property (strong, nonatomic, readwrite) UIButton *button0;
@end

@implementation NumPadView
- (instancetype)init
{
    self = [super init];
    if (self) {
        self.button1 = [[UIButton alloc] initWithFrame:CGRectZero];
        self.button1.backgroundColor = [UIColor redColor];
        //...
    }
    return self;
}

- (void)layoutSubviews {
    self.button1.frame = //...
    //...
}
@end

但是,我总是将布局/ UI设计作为最后一步,因为我想确保一切都先发挥作用。因此,我会花时间在NumPadViewController中实施方法,而不是在NumPadView中编写布局。当然,要测试视图控制器的功能,我需要某种UI来进行交互。我想使用.xib文件创建一个快速原型UI并将其附加到NumPadView。我根本不想更改NumPadView的界面,因为这需要更改NumPadViewController。所以我的问题是弄清楚如何在 NumPadView实现中从创建和加载.xib。当然,.xibs通常由视图控制器拥有,IBOutlets链接到所述视图控制器中的属性,但我想将所有这些转移到NumPadView的私有实现,如下所示:

//
//  NumPadView.m

#import "NumPadView.h"

@interface NumPadView ()
//Link private interface properties to .xib file
@property (strong, nonatomic, readwrite) IBOutlet UIButton *button1;
@property (strong, nonatomic, readwrite) IBOutlet UIButton *button2;
@property (strong, nonatomic, readwrite) IBOutlet UIButton *button3;
@property (strong, nonatomic, readwrite) IBOutlet UIButton *button4;
@property (strong, nonatomic, readwrite) IBOutlet UIButton *button5;
@property (strong, nonatomic, readwrite) IBOutlet UIButton *button6;
@property (strong, nonatomic, readwrite) IBOutlet UIButton *button7;
@property (strong, nonatomic, readwrite) IBOutlet UIButton *button8;
@property (strong, nonatomic, readwrite) IBOutlet UIButton *button9;
@property (strong, nonatomic, readwrite) IBOutlet UIButton *button0;
@end

@implementation NumPadView
- (instancetype)init
{
    //I'm not sure if this is the right way to do it, but I'm looking for something similar in effect.
    self = [[NSBundle mainBundle] loadNibNamed:[NSString stringWithFormat:@"%@", [self class]] owner:self options:nil].firstObject;
    return self;
}
@end

那么,我该如何有效地实现这个呢?我已尝试使用loadFromNib:,但按钮属性始终为nil。我已在界面构建器中连接了所有IBOutlet,并将NumPadView.xib上的文件所有者设置为NumPadView,将主视图的类设置为UIScrollView(我已尝试{{1}同样)。除了关于如何成功实施这个方案的建议之外,如果有人有更好的方法,我当然可以开辟更好的方法来做这整个原型设计方案。最重要的是NumPadView维护一致的接口,NumPadView不知道.xib文件。 this onethis one等类似问题似乎忽略了这一概念。谢谢您的意见;我期待着阅读你的答案。

1 个答案:

答案 0 :(得分:2)

你不能做你正在做的事情,因为这不是笔尖加载的工作方式。笔尖有文件所有者。对外部世界的出口,就是那个所有者。因此,如果NumPadView是nib中的顶级对象,那么NumPadView不能是所有者,因为你最终得到的是另一个 NumPadView(nib中的那个)。如果另一个对象是所有者 - 这是常见的事情 - 那么出口不应该从按钮到文件的所有者,这将是毫无意义的,而是对于笔尖中的NumPadView 。 (通常还需要在笔尖中的NumPadView出口到文件的所有者,以便所有者可以从笔尖检索NumPadView并使用它做一些事情。)

所以你需要考虑你的网点连接在笔尖的哪个位置, 文件的所有者是什么类(什么类),以及实际所有者处于加载时。如果你相应地构建了东西,那么它们在笔尖的内部世界和装载机的外部世界中相匹配,一切都会很好。