在自包含的自定义 UIView 子类中使用 .xib 文件进行原型设计
Posted
技术标签:
【中文标题】在自包含的自定义 UIView 子类中使用 .xib 文件进行原型设计【英文标题】:Using a .xib File in a Self-Contained Custom UIView Subclass for Prototyping Purposes 【发布时间】:2015-01-07 18:49:59 【问题描述】:根据我的经验,最强大的视图/视图控制器实现直接在 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
。我已经连接了界面构建器中的所有 IBOutlets,并将NumPadView.xib
上的文件所有者设置为NumPadView
,并将主视图的类设置为UIScrollView
(我也尝试过NumPadView
)。除了关于如何成功实施这个方案的建议之外,如果有人有更好的方法,我当然愿意用更好的方法来完成整个原型设计方案。最重要的是NumPadView
保持一致的界面,NumPadViewController
不知道.xib 文件。在this one 和this one 等类似问题中似乎忽略了这个概念。谢谢您的意见;我期待着阅读您的答案。
【问题讨论】:
P.S.请了解阵列和插座集合。无需 10 个单独的插座属性。 谢谢,但我更喜欢明确一点。 【参考方案1】:你不能完全做你正在做的事情,因为这不是 nib 加载的工作方式。一个笔尖有一个文件的所有者。可以说,通往外部世界的出口是给那个所有者的。因此,如果 NumPadView 是 nib 中的***对象,则 NumPadView 不能成为所有者,因为您最终得到的是 another NumPadView(nib 中的那个)。如果 another 对象是所有者 - 这是通常的事情 - 那么出口不应该从按钮到文件所有者,这将毫无意义,而是到 nib 中的 NumPadView。 (通常还需要从 nib 中的 NumPadView 到文件所有者的出口,以便所有者可以从 nib 检索 NumPadView 并对其进行处理。)
所以你需要考虑一下你的插座在笔尖中的位置,什么文件的所有者是(什么类),以及谁实际所有者在加载时间。如果你相应地构造事物,使它们在 nib 的内部世界和 loader 的外部世界中匹配,一切都会好起来的。
【讨论】:
进一步讨论,以及从 nib 加载和检索任意对象的示例,此处:apeth.com/iosBook/ch07.html#_nib_loading_and_file_8217_s_owner 当然,这种事情是我们总是为笔尖中的表格视图单元格所做的事情:apeth.com/iOSBook/ch21.html#_designing_a_cell_in_a_nib 你知道有什么更好的方法来制作 UI 原型吗?谢谢。 你做的很棒。正如我在回答中所说,您只需要构建您的笔尖并正确且一致地加载即可。以上是关于在自包含的自定义 UIView 子类中使用 .xib 文件进行原型设计的主要内容,如果未能解决你的问题,请参考以下文章
在 Storyboard 中设计的自定义 UITableViewCell 中的自定义 UIView
UIView beginAnimations 在自定义属性上太快了
使用来自 XIB 的自定义 NSView/UIView 子类?
何时在自定义 UIVIew 中添加 CAAnimation?
如何让 UITableViewCell 在自定义 UIView 子类上调用 setHighlighted 或 setSelected?