自定义View的封装和xib文件的使用详解|xiaoyou's blog
纯代码封装自定义View和XIB封装自定义View的区别 - CSDN博客
转载于:https://www.cnblogs.com/louyizhidu/p/9151620.html
xib(只负责创建控件,不实现功能)
创建xib文件的方式 1.在创建文件的时候,选择also create xib file 就会自动创建一个xib文件,文件和xib关联好了,直接用就可以了 2.需要在empty里创建一个xib文件,然后指定files owner,然后向文件里拖拽一个view,最后指定owner的self.view是哪个view
auto layout ----->横竖屏切换 size class --------->当前屏幕尺寸的适配
// // bundle如果写成nil,就是默认路径,默认路径就是[NSBundle mainbundle]; // ViewController *vc = [[ViewController alloc] initWithNibName:NSStringFromClass([ViewController class]) bundle:nil]; // self.window.rootViewController = vc;
可以用nib创建tableView,使用自定义的cell,使用方法都很类似,只是需要先找到nib文件,然后在文件里找到当前需要注册的cell
// 先找到nib文件 UINib *nib = [UINib nibWithNibName:NSStringFromClass([MovieCell class]) bundle:nil]; // 在文件里找到当前需要注册的cell [self.myTableView registerNib:nib forCellReuseIdentifier:@"MovieCell"]; [self createData];
如果是单独创建的xib文件,想要显示的话
NSArray *arr = [[NSBundle mainBundle] loadNibNamed:@"MyView" owner:nil options:nil]; // NSLog(@"%@", arr);
xib创建的视图,放在一个数组中
<span style="font-size:18px;"> UILabel *label = arr[0]; [self.view addSubview:label]; label.center = CGPointMake(150, 500); UIImageView *imageView = arr[1]; [self.view addSubview:imageView];</span>
1.1. 什么是xib?

xib就是一种文件的后缀,我们要使用Interface Builder工具对它进行编辑。xib的作用就是描绘页面中的布局,可以让我们及时看到效果,并且也比代码要方便快速的多。
当我们使用MVC模式去编写项目的时候,创建了一个UIViewController,它就是MVC中的C,还需要创建一个View,表示MVC中的V。之前我们的做法都是继承UIView类,创建一个自定义View,然后把所有有关视图的代码都写到自定义View中,虽然把Controller类进行了瘦身,但是View中的代码依然看起来让人头疼,每添加一个小控件都需要好几行的代码,一个简单的登录页面,就需要一大段的代码,很烦人。不过有了xib,我们做一个登录页面出来,不仅不需要写代码了,还可以通过拖线的方式把属性、方法都生成,非常的方便。
1.2. nib又是什么东东?
项目进行编译之后,xib文件会保存到我们的Bundle中,被编译成了nib文件,

简单来说,xib就是编译之前的格式,nib就是编译之后的格式。至于你到底叫它xib还是nib,都随你喜欢啦
1.3. 如何使用 1.3.1 xib文件的创建
当我们创建视图控制器的时候,我们把这个选项选中,

这样我们就可以创建一个自带xib文件的视图控制器了。
如果说创建视图控制器的时候忘记勾选了,也不要着急,我们可以单独创建一个xib文件,

单独创建xib文件的时候,名字最好和它所对应的控制器相同。
注意,虽然你单独创建出来了xib文件,但是需要注意的是,我们还要将xib和控制器类进行关联,
在Class中输入xib对应的控制器的类名,

除了这个,还有:在File’s Owner上右击,会出现黑色的HUD,找到view,右侧有个小圈圈,鼠标放到上面会变成小加号,拖动到xib上。

NOTE:
自己创建的xib与控制器关联需要两步:
将xib与自己的控制器类进行关联
xib的view与控制器的view进行关联
1.3.2 控件的添加
使用方式就是大家经常所说的托控件,只需要将右下角的控件拖到我们页面中:

我们把控件都摆放好位置之后,运行会发现并不是居中的,这是因为我们Size Classes的关系,大家暂时先不用管,你要做的就是把所有的控件往左边靠,然后摆个大概的位置就好了。
1.3.3 控件与属性或者事件的绑定
当我们摆放好控件的位置之后,就可以运行看效果了,这个时候效果都出现没有问题,但是我们会发现点击的时候没有作用,那是因为我们还没有给控件绑定事件,那么,该如何做呢?
打开Assistant Editor编辑模式,也就是同时可以显示两个类的文件的模式,左侧显示我们的xib文件,右侧显示xib文件对应的控制器。
正式开始拖线,选中要生成属性的控件,按住Control键,拖动到右侧,就会出现如下效果:

松开手后,你会看到这样一个框:

connection中选择默认的Outlet,意思是生成一个属性。然后在Name中输入属性的名字,其它地方不用修改,选择,Connect按钮。这样我们就将控件与控制器中的一个属性关联起来了。

拖动按钮的事件几乎相同,选中一个button,然后按住Control键进行拖动,刚刚connection中不再是选择Outlet,而是选择Action,Name的位置填写事件方法的名称,type的位置填写生成方法的参数类型,其它默认,然后点击Connect按钮,进行事件的创建。
创建好了事件之后,我们去实现事件方法,效果很简单:点击按钮,显示输入的用户名和密码:
#pragma mark - 按钮事件
#pragma mark 登录
- (IBAction)loginButtonAction:(UIButton *)sender
{
NSString *messageStr = [NSString stringWithFormat:@"%@\n%@", _userNameTextField.text, _passwordTextField.text];
UIAlertController *alertC = [UIAlertController alertControllerWithTitle:@"提示" message:messageStr preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAlertAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
NSLog(@"取消按钮");
}];
[alertC addAction:cancelAlertAction];
[self showDetailViewController:alertC sender:nil];
}
1.4. 这个东西有什么优点?
xib让我们创建应用程序的页面更加的快速,节省了更多的时间
快速的帮助我们创建出来了属性和方法,还是节省了很多的时间
xib比较简洁,只描述了当前页面的一些内容
所见即所得,比代码直观
view.xib的说明
View的custom cass是关联自身的 File’s owner是关联任意类的方式一.xib拖xib 用File’s owner
方式二.代码加载,不向某个控制器关联控件 用View的custom class一.代码加载XIB
1).只有xib文件
1.只有View1.xib文件
2.File’s Owner 和View1的Custom class都未设置加载View的方法
UIView *v1 = [[[NSBundle mainBundle] loadNibNamed:@"View1" owner:nil options:nil] lastObject];
2).有xib****( .h 和.m )
****文件
1.有View11.xib View11.h View11.m文件
2.File’s Owner 和View1的Custom class都未设置加载View的方法
UIView *v11 = [[[NSBundle mainBundle] loadNibNamed:@"View11" owner:nil options:nil] lastObject];
3).有xib文件,设置了File’s Owner
1.有View2.xib文件
2.A.File’s Owner 为ViewController (File’s Owner关联ViewController.xib,可以向 VIewController.h或ViewCOntroller.m拖线)
B. 或者设置为UIViewController3.View2的Custom class未设置
A种情况 某个ViewController的View
ViewControler加载View方法
UIView *v2 = [[[NSBundle mainBundle] loadNibNamed:@"View2" owner:self options:nil] lastObject];
B种情况 公共的
加载View方法
UIView *v2 = [[UIViewController alloc] initWithNibName: @"View2" bundle:nil].view;
- .有xib( .h 和.m ) 文件,设置了File’s Owner 和 View的Custom Class**
1.有View3.xib文件 View3.h View3.m
2.File’s Owner设置为 A.ViewContoller
或者 B.UIViewController)
3.View3的Custom class 设置为 VIew3 (xib可以向 View3.h或View3.m拖线)A种情况 某个ViewController的View
ViewControler加载View方法
UIView *v3 = [[[NSBundle mainBundle] loadNibNamed: @"View3" owner:self options:nil] lastObject];
B种情况 公共的 需要将view和File’s Owner连线
加载View方法
UIView *v3 = [[UIViewController alloc] initWithNibName: @"View3" bundle:nil].view;
注:
当新建AViewController类时默认生成
1.AViewController.h 和 AViewController.m文件
2.AViewController.xib
即可 [[AViewController alloc] initWithNibName:@"" bundle:nil]5).有xib( .h 和.m ) 文件,设置了File’s Owner
1.有View3.xib文件 View3.h View3.m
2.File’s Owner(File’s Owner可以设置为A.ViewContoller 或者 B.UIViewController)其他controller使用代码:[UINib nibWithNibName:@"CycleScrollView"bundle:nil]
XIB拖XIB
一 .通过父View的Custom Class (XIB拖XIB) 有缺陷,不用
ViewController
加载xib时候会触发一些方法,如:
- (id)initWithCoder:(NSCoder *)aDecoder - (id)awakeAfterUsingCoder:(NSCoder*)aDecoder
可以在-awakeAfterUsingCoder:(NSCoder*)aDecoder里通过 nibName 获取xib实例并加以替换
1.新建CustomView.h
CustomView.m
CustomView.xib2.设置
CustomView.xib里父View
的Custom Class为
CustomView 设置其他Xib或StoryBoard里
View的 Custom Class为CustomView3.在 CustomView
.m 文件里附上代码
- (id) awakeAfterUsingCoder:(NSCoder)aDecoder {
BOOL theThingThatGotLoadedWasJustAPlaceholder = ([[self subviews] count] == 0);
if (theThingThatGotLoadedWasJustAPlaceholder) {
SubView theRealThing = [[self class] loadFromNibNoOwner];
// pass properties through [self copyUIPropertiesTo:theRealThing]; //auto layout self.translatesAutoresizingMaskIntoConstraints = NO; theRealThing.translatesAutoresizingMaskIntoConstraints = NO; return theRealThing; } return self; } -(void) copyUIPropertiesTo:(UIView *)view { // reflection did not work to get those lists, so I hardcoded them // any suggestions are welcome here NSArray *properties = [NSArray arrayWithObjects: @"frame",@"bounds", @"center", @"transform", @"contentScaleFactor", @"multipleTouchEnabled", @"exclusiveTouch", @"autoresizesSubviews", @"autoresizingMask", @"clipsToBounds", @"backgroundColor", @"alpha", @"opaque", @"clearsContextBeforeDrawing", @"hidden", @"contentMode", @"contentStretch", nil]; // some getters have 'is' prefix NSArray *getters = [NSArray arrayWithObjects: @"frame", @"bounds", @"center", @"transform", @"contentScaleFactor", @"isMultipleTouchEnabled", @"isExclusiveTouch", @"autoresizesSubviews", @"autoresizingMask", @"clipsToBounds", @"backgroundColor", @"alpha", @"isOpaque", @"clearsContextBeforeDrawing", @"isHidden", @"contentMode", @"contentStretch", nil]; for (int i=0; i<[properties count]; i++) { NSString * propertyName = [properties objectAtIndex:i]; NSString * getter = [getters objectAtIndex:i]; SEL getPropertySelector = NSSelectorFromString(getter); NSString *setterSelectorName = [propertyName stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[propertyName substringToIndex:1] capitalizedString]]; setterSelectorName = [NSString stringWithFormat:@"set%@:", setterSelectorName]; SEL setPropertySelector = NSSelectorFromString(setterSelectorName); if ([self respondsToSelector:getPropertySelector] && [view respondsToSelector:setPropertySelector]) { NSObject * propertyValue = [self valueForKey:propertyName]; [view setValue:propertyValue forKey:propertyName]; } } }
**二 .通过file’s owner的Custom Class (XIB拖XIB)
**
通过重载 initWithCoder方法来实现,因为通过 xib 来创建一个对象会调用到这个方法,所以我们需要在这个方法里做一些处理,把这个 CustomView的 xib中的内容加载进来,这时同样是需要通过代码来来加载1.新建CustomView.h
CustomView.m
CustomView.xib2.设置
CustomView.xib里file’s owner的Custom Class为 CustomView 设置其他Xib或StoryBoard里View的 Custom Class为CustomView
3.在 CustomView
.m 文件里附上代码
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]) {
UIView *containerView = [[[UINib nibWithNibName:@"CustomView" bundle:nil] instantiateWithOwner:self options:nil] objectAtIndex:0];
CGRect newFrame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
containerView.frame = newFrame;
[self addSubview:containerView];
}
return self;
}