纯代码封装自定义View和XIB封装自定义View的区别
2016-07-20 11:20
302 查看
一、背景
如果一个view内部的子控件比较多,一般会考虑自定义一个view,把它内部子控件的创建屏蔽起来,不让外界关心,
外界可以传入对应的模型数据给view,view拿到模型数据后给内部的子控件设置对应的数据
二、纯代码封装View
1.封装控件的基本步骤
(1).在initWithFrame:方法中添加子控件,提供便利构造方法
(2).在layoutSubviews方法中设置子控件的frame(一定要调用super的layoutSubviews)
(3).增加模型属性,在模型属性set方法中设置数据到子控件上
2.编写代码需要注意
系统的调用流程:initWithFrame: —> layoutSubviews
(1).当重写init方法,用于创建和初始化子控件,在通过init方法创建View时,系统也会先调用对象的initWithFrame:方法,再调用对象的init方法;如果直接调用initWithFrame:方法初始化对象,则不会调用去调用init方法
(2).不能通过重写init方法设置子控件的Frame,因为系统是先调用initWithFrame:方法,initWithFrame:方法创建的对象Frame值默认为0,如果子控件的Frame不依赖于父控件的Frame就可以设置,但是一般都是通过父控件的Frame计算子控件的Frame
(3).不能通过重写initWithFrame:方法设置子控件的Frame,因为设置的子控件的Frame只有效一次,如果父控件的Frame被再次的修改了,就会调用layoutSubviews方法重新设置子控件的Frame,在layoutSubviews方法中没有重新设置子控件的Frame,且子控件的Frame与父控件的Frame有依赖,子控件的Frame就会被设置为0;如果要让子控件的Frame永远有效,子控件的Frame只要不依赖于父控件的Frame就可以,但是一般都是通过父控件的Frame计算子控件的Frame
(4).如果子控件的Frame依赖于父控件的Frame,就必须在layoutSubviews方法里面给子控件的Frame设置值
(5).系统不会去调用nitWithCoder:和awakeFromNib方法
3.代码举例
三、XIB封装一个自定义的View
1.封装控件的基本步骤
(1).新建自定义控件类,必须继承自与之相关的类;如:封装的是view就要继承自UIView
(2).新建XIB文件,自定义View,修改xib中view的类名为新建的自定义控件类
(3).增加模型属性,在模型属性set方法中设置数据到子控件上
2.XIB的加载方法
方法1
NSArray *views = [[NSBundle mainBundle] loadNibNamed:@”xib文件名” owner:nil options:nil];
方法2
UINib *nib = [UINib nibWithNibName:@”xib文件名” bundle:nil];
NSArray *views = [nib instantiateWithOwner:nil options:nil];
3.编写代码需要注意
系统的调用流程: initWithCoder —> awakeFromNib —> layoutSubviews
(1).加载XIB后,系统会自动调用 - (id)initWithCoder:(NSCoder *)aDecoder 方法来初始化控件,其中aDecoder是一个解析器,对XIB进行解析;不能在这个方法中给XIB里自定义view的子控件进行初始化,因为initWithCoder:方法是‘处于正在初始化’,有些细节还没有初始化完毕,可能还没给子控件进行连线等;还可以在initWithCoder:方法里代码创建子控件并进行初始化,但不能设置它的Frame值;一般XIB的初始化操作在awakeFromNib里进行
(2).如过还需要用代码添加子控件,可以通过重写initWithCoder:方法,在方法里面用代码添加子控件和初始化,添加的子控件的Frame值也要在layoutSubviews方法里设置。
(3).当控件从XIB中创建完毕后会调用awakeFromNib方法,XIB的所有的初始化操作应该在这个方法里进行,但不能在这个方法中对子控件设置Frame的值
(4).如果需要重新设置子控件的Frame值,应该在layoutSubviews方法里进行设置,因为父控件的Frame只要改变就就会调用该方法
(5).用XIB封装自定义的View,控件从XIB中创建的过程不会调用init方法和initWithFrame:方法
(6).XIB里自定义View必须设置成自动布局,即把View的 ‘Show the File inspector’ 里面的 ‘Use Auto Layout’ 前面的钩去掉;这样设置后才可以在layoutSubviews里重新设置自定义View的子控件Button的Frame值
4.XIB封装自定义的View具体实现
(1).创建XIB,并自定义View和其子控件
A.设计自定义View的类并与类的属性连线
B.设置自定义View为可变的尺寸、隐藏电池图标,View的背景色
C.设置子控件的背景色
D.设置子控件的尺寸
E.关闭自动布局(Autolayout),才可以在layoutSubviews里重新设置Button的Frame值
5.新建自定义控件类的代码如下
如果一个view内部的子控件比较多,一般会考虑自定义一个view,把它内部子控件的创建屏蔽起来,不让外界关心,
外界可以传入对应的模型数据给view,view拿到模型数据后给内部的子控件设置对应的数据
二、纯代码封装View
1.封装控件的基本步骤
(1).在initWithFrame:方法中添加子控件,提供便利构造方法
(2).在layoutSubviews方法中设置子控件的frame(一定要调用super的layoutSubviews)
(3).增加模型属性,在模型属性set方法中设置数据到子控件上
2.编写代码需要注意
系统的调用流程:initWithFrame: —> layoutSubviews
(1).当重写init方法,用于创建和初始化子控件,在通过init方法创建View时,系统也会先调用对象的initWithFrame:方法,再调用对象的init方法;如果直接调用initWithFrame:方法初始化对象,则不会调用去调用init方法
(2).不能通过重写init方法设置子控件的Frame,因为系统是先调用initWithFrame:方法,initWithFrame:方法创建的对象Frame值默认为0,如果子控件的Frame不依赖于父控件的Frame就可以设置,但是一般都是通过父控件的Frame计算子控件的Frame
(3).不能通过重写initWithFrame:方法设置子控件的Frame,因为设置的子控件的Frame只有效一次,如果父控件的Frame被再次的修改了,就会调用layoutSubviews方法重新设置子控件的Frame,在layoutSubviews方法中没有重新设置子控件的Frame,且子控件的Frame与父控件的Frame有依赖,子控件的Frame就会被设置为0;如果要让子控件的Frame永远有效,子控件的Frame只要不依赖于父控件的Frame就可以,但是一般都是通过父控件的Frame计算子控件的Frame
(4).如果子控件的Frame依赖于父控件的Frame,就必须在layoutSubviews方法里面给子控件的Frame设置值
(5).系统不会去调用nitWithCoder:和awakeFromNib方法
3.代码举例
---------- 封装自定义的View的.h文件 #import <UIKit/UIKit.h> #import "SSData.h" @interface ANewView : UIView @property (nonatomic,strong) SSData *data; + (instancetype)aNewView; @end ---------- 封装自定义的View的.m文件 #import "ANewView.h" @interface ANewView () @property (nonatomic,strong) UIButton *button; @property (nonatomic,strong) UILabel *lable; @end @implementation ANewView + (instancetype)aNewView { return [[self alloc] init]; } //重写initWithFrame:方法创建子控件和初始化子控件的属性(除属性Frame的值不可以在此设置) - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { //创建子控件button self.button = [[UIButton alloc] init]; self.button.backgroundColor = [UIColor orangeColor]; [self addSubview: self.button]; //创建子控件Lable self.lable = [[UILabel alloc] init]; self.lable.backgroundColor = [UIColor yellowColor]; self.lable.textAlignment = NSTextAlignmentCenter; [self addSubview:self.lable]; } return self; } //只要父控件的Frame发生改变,就会调用layoutSubviews方法 //重写layoutSubviews方法,给子控件的Frame设置值 - (void)layoutSubviews { [super layoutSubviews]; //设置子控件的Frame CGFloat superW = self.frame.size.width; CGFloat superH = self.frame.size.height; self.button.frame = CGRectMake(0, 0, superW, superH / 2); self.lable.frame = CGRectMake(0, superH / 2 + 5, superW, superH - (superH / 2 + 5)); } //重写set方法给子控件设置数据 - (void)setData:(SSData *)data { //必须先给成员变量赋值,不赋值,以后调用get方法取值就取不到值 _data = data; //设置成员变量的数据 [self.button setTitle:data.buttonStr forState:UIControlStateNormal]; self.lable.text = data.lableStr; } @end ---------- 数据模型的.h文件 #import <Foundation/Foundation.h> @interface SSData : NSObject @property (nonatomic,strong) NSString *buttonStr; @property (nonatomic,strong) NSString *lableStr; @end ---------- 数据模型的.m文件 #import "SSData.h" @implementation SSData @end ---------- 调用自定义的View #import "ViewController.h" #import "ANewView.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //数据模型 SSData *dataView = [[SSData alloc] init]; dataView.buttonStr = @"Hello"; dataView.lableStr = @"World"; //创建View ANewView *newView = [[ANewView alloc] init]; newView.frame = CGRectMake(100,100, 200, 100); newView.backgroundColor = [UIColor blueColor]; newView.data = dataView; [self.view addSubview:newView]; //重新给View对象赋值 dataView.buttonStr = @"天天"; dataView.lableStr = @"编程"; newView.frame = CGRectMake(80,200, 250, 100); newView.data = dataView; } @end
三、XIB封装一个自定义的View
1.封装控件的基本步骤
(1).新建自定义控件类,必须继承自与之相关的类;如:封装的是view就要继承自UIView
(2).新建XIB文件,自定义View,修改xib中view的类名为新建的自定义控件类
(3).增加模型属性,在模型属性set方法中设置数据到子控件上
2.XIB的加载方法
方法1
NSArray *views = [[NSBundle mainBundle] loadNibNamed:@”xib文件名” owner:nil options:nil];
方法2
UINib *nib = [UINib nibWithNibName:@”xib文件名” bundle:nil];
NSArray *views = [nib instantiateWithOwner:nil options:nil];
3.编写代码需要注意
系统的调用流程: initWithCoder —> awakeFromNib —> layoutSubviews
(1).加载XIB后,系统会自动调用 - (id)initWithCoder:(NSCoder *)aDecoder 方法来初始化控件,其中aDecoder是一个解析器,对XIB进行解析;不能在这个方法中给XIB里自定义view的子控件进行初始化,因为initWithCoder:方法是‘处于正在初始化’,有些细节还没有初始化完毕,可能还没给子控件进行连线等;还可以在initWithCoder:方法里代码创建子控件并进行初始化,但不能设置它的Frame值;一般XIB的初始化操作在awakeFromNib里进行
(2).如过还需要用代码添加子控件,可以通过重写initWithCoder:方法,在方法里面用代码添加子控件和初始化,添加的子控件的Frame值也要在layoutSubviews方法里设置。
(3).当控件从XIB中创建完毕后会调用awakeFromNib方法,XIB的所有的初始化操作应该在这个方法里进行,但不能在这个方法中对子控件设置Frame的值
(4).如果需要重新设置子控件的Frame值,应该在layoutSubviews方法里进行设置,因为父控件的Frame只要改变就就会调用该方法
(5).用XIB封装自定义的View,控件从XIB中创建的过程不会调用init方法和initWithFrame:方法
(6).XIB里自定义View必须设置成自动布局,即把View的 ‘Show the File inspector’ 里面的 ‘Use Auto Layout’ 前面的钩去掉;这样设置后才可以在layoutSubviews里重新设置自定义View的子控件Button的Frame值
4.XIB封装自定义的View具体实现
(1).创建XIB,并自定义View和其子控件
A.设计自定义View的类并与类的属性连线
B.设置自定义View为可变的尺寸、隐藏电池图标,View的背景色
C.设置子控件的背景色
D.设置子控件的尺寸
E.关闭自动布局(Autolayout),才可以在layoutSubviews里重新设置Button的Frame值
5.新建自定义控件类的代码如下
---------- 新建自定义控件类的.h文件 #import <UIKit/UIKit.h> #import "SSData.h" @interface ANewView : UIView @property (nonatomic,strong) SSData *data; + (instancetype)aNewView; @end ---------- 新建自定义控件类的.m文件 #import "ANewView.h" @interface ANewView () @property (weak, nonatomic) IBOutlet UIButton *button; @property (nonatomic,weak) IBOutlet UILabel *lable; @property (nonatomic,strong) UIImageView *imageView; @end @implementation ANewView + (instancetype)aNewView { //方式一 //ANewView *view = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self) owner:nil options:nil] lastObject]; //方式二 UINib *nib = [UINib nibWithNibName:NSStringFromClass(self) bundle:nil]; ANewView *view = [[nib instantiateWithOwner:nil options:nil]lastObject]; return view; } //重写initWithCoder:用代码添加子控件 - (id)initWithCoder:(NSCoder *)aDecoder { if (self = [super initWithCoder:aDecoder]) { //可以用代码创建子控件并对其初始化 self.imageView = [[UIImageView alloc] init]; [self addSubview:self.imageView]; self.imageView.backgroundColor = [UIColor yellowColor]; } return self; } //当XIB完全初始化完毕后,会调用这个方法,可以在这个方法中对XIB的子控件进行初始化 -(void)awakeFromNib { //一定要调用父类的awakeFromNib方法 [super awakeFromNib]; self.button.backgroundColor = [UIColor yellowColor]; self.lable.backgroundColor = [UIColor orangeColor]; } //给子控件重新布局 - (void)layoutSubviews { //一定要调用父类的layoutSubviews方法 [super layoutSubviews]; //设置子控件的Frame CGFloat superW = self.frame.size.width; CGFloat superH = self.frame.size.height; //XIB里自定义View必须设置成自动布局,不然Button的Frame不能成功赋值 self.button.frame = CGRectMake(0, 0, superW, superH / 3 - 5); CGFloat lableY = self.button.frame.origin.y + self.button.frame.size.height + 5; self.lable.frame = CGRectMake(0, lableY, superW, superH / 3 - 5); CGFloat imageY = self.lable.frame.origin.y + self.lable.frame.size.height + 5; self.imageView.frame = CGRectMake(0,imageY, superW, superH / 3 - 5); } //重写set方法给子控件设置数据 - (void)setData:(SSData *)data { //必须先给成员变量赋值,不赋值,以后调用get方法取值就取不到值 _data = data; //设置成员变量的数据 [self.button setTitle:data.buttonStr forState:UIControlStateNormal]; self.lable.text = data.lableStr; } @end ---------- 数据模型的.h文件 #import <Foundation/Foundation.h> @interface SSData : NSObject @property (nonatomic,strong) NSString *buttonStr; @property (nonatomic,strong) NSString *lableStr; @end ---------- 数据模型的.m文件 #import "SSData.h" @implementation SSData @end ---------- XIB封装的自定义View的调用 #import "ViewController.h" #import "ANewView.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //数据模型 SSData *dataView = [[SSData alloc] init]; dataView.buttonStr = @"Hello"; dataView.lableStr = @"World"; //创建View ANewView *newView = [ANewView aNewView]; newView.frame = CGRectMake(100,100, 200, 100); newView.data = dataView; [self.view addSubview:newView]; //重新给View对象赋值 dataView.buttonStr = @"天天"; dataView.lableStr = @"编程"; newView.frame = CGRectMake(80,200, 250, 200); newView.data = dataView; } @end
相关文章推荐
- flex 控件的重要属性
- 学习Winform文本类控件(Label、Button、TextBox)
- Delphi控件ListView的属性及使用方法详解
- web下载的ActiveX控件自动更新
- WinForm实现按名称递归查找控件的方法
- C#中父窗口和子窗口之间控件互操作实例
- C#编写ActiveX网页截图控件
- Android编程之Button控件用法实例分析
- Android控件之CheckBox、RadioButton用法实例分析
- 在Android开发中使用自定义组合控件的例子
- 一款超酷的Android自定义加载控件
- Android重写View实现全新的控件
- MFC中动态创建控件以及事件响应实现方法
- WinForm自定义函数FindControl实现按名称查找控件
- Android控件之ProgressBar用法实例分析
- WinForm拖拽控件生成副本的解决方法
- ASP.NET动态添加用户控件的方法
- WinForm遍历窗体所有子控件的方法
- ASP.NET的HtmlForm控件学习及Post与Get的区别概述
- 浅析Bootstrap验证控件的使用