StoryBoard和Interface Builder为iOS开发带来了极大的便利,今天就给大家介绍一个使用Interface Builder的技巧:
使用xib创建可复用View。
在项目开发中,我们经常需要创建一些可复用的view,比较简单的话代码写写也是很快,但如果比较复杂的话,使用Interface Builder创建一个xib文件来制作就快捷很多,但是传统的方法生成的view只属于xib的File’s Owner, 没有办法复用。
举个例子,项目有多个页面需要使用一个控件(UIView)来展示一张公交卡的信息, 界面如下:
可以看到这个界面如果用代码写的话还是要花不少功夫的,而且要支持AutoLayout的话,即使有Masonry,代码的长度也可想而知。而使用xib来创建的话相对会容易很多。用xib创建一个这样的页面,相信大家都会,下面我们来看如何让创建的view既支持通过init方法使用,又支持直接在其他xib或者storyboard文件使用。我们给这个view取个名字,就叫“CardView”吧。
(示例代码: https://github.com/TravelC/XibReuseableViewDemo)
1. 创建CardView.xib文件,并创建好页面,设置好约束
2. 创建UIView的子类CardView,设置CardView.xib的File’s Owner为CardView
注意这里的CardView是UIView的子类,并不是UIViewController的子类。
3. 设置我们的cardView为CardView类的一个IBOutlet,这里取名为view
4. 打开CardView.m,重写初始化方法
这里重写了从代码创建会使用init、initWithFrame方法,以及在xib或者storyboard用到的initWithCoder方法。下面的示例代码封装了一个loadCardViewFromNib方法,用来从xib加载view以及做一些初始化操作(增加了一个灰色的边框并设置圆角)。
CardView.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #import <UIKit/UIKit.h> @interface CardView : UIView @property (strong, nonatomic) IBOutlet UIView *view; @property (weak, nonatomic) IBOutlet UILabel *cardTypeLabel; @property (weak, nonatomic) IBOutlet UILabel *cardNameLabel; @property (weak, nonatomic) IBOutlet UILabel *cardNoLabel; @property (weak, nonatomic) IBOutlet UILabel *cardMoneyLabel; @property (weak, nonatomic) IBOutlet UILabel *numOfOpenedProductLabel; @property (weak, nonatomic) IBOutlet UILabel *awardRecordLabel; @property (weak, nonatomic) IBOutlet UIImageView *certificatedImageView; @property (weak, nonatomic) IBOutlet UILabel *certificatedLabel; @property (weak, nonatomic) IBOutlet UIButton *certificateButton; @property (weak, nonatomic) IBOutlet UIButton *modifyCardInfoButton; @property (weak, nonatomic) IBOutlet UIView *cardTypeBgView; @end
|
CardView.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| #import "CardView.h" @interface CardView () @property BOOL isCardViewLoadedFromNib; @end @implementation CardView // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */ - (void)loadCardViewFromNib { if (!self.isCardViewLoadedFromNib) { [[NSBundle mainBundle] loadNibNamed:@"CardView" owner:self options:nil]; [self addSubview:self.view]; self.view.layer.borderWidth = 0.5; self.view.layer.borderColor = [UIColor lightGrayColor].CGColor; self.view.layer.cornerRadius = 5.0; self.isCardViewLoadedFromNib = YES; } } - (instancetype)init { self = [super init]; if (self) { [self loadCardViewFromNib]; } return self; } - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self loadCardViewFromNib]; CGRect viewFrame = CGRectMake(0, 0, frame.size.width, frame.size.height); self.view.frame = viewFrame; } return self; } - (instancetype)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { [self loadCardViewFromNib]; } return self; }
|
可以看到,在loadCardViewFromNib里面,我们事实上从CardView.xib初始化了一个view(IBOutlet那个),并把它当做subView加到了CardView的实例上面。同时,在CardView.h里面我们设置了一系列的IBOutlet,以方便CardView的后续使用。
5. 在代码中使用CardView
在代码中使用CardView,相当方便,像你使用UIView一样来使用即可,这里给出一个通过initWithFrame方法创建的例子:
1 2
| CardView *cardView = [[CardView alloc] initWithFrame:CGRectMake(10.0, 70.0, 300.0, 186.0)]; [self.view addSubview:cardView];
|
6. 在xib或者storyboard中使用CardView
拖拽一个UIView,将它的类改成CardView即可,唯一的缺点就是不能在xib或者storyboard中预览CardView,现实的实际是空白的UIView,但在程序运行时是CardView真实的样子。
7. 示例项目代码及截图
代码请到Github下载: https://github.com/TravelC/XibReuseableViewDemo
截图: