隨機(jī)配圖
導(dǎo)讀:
iOS開(kāi)發(fā)中,很多時(shí)候系統(tǒng)提供的控件并不能很好的滿足我們的需求,因此,自定義控件便成為搭建UI界面中必不可少的一部分。本篇博文以筆記的形式,總結(jié)了自定義控件的兩種方式以及每種方式的實(shí)現(xiàn)步驟,雖簡(jiǎn)略卻不簡(jiǎn)單,因此希望留給讀者更多的思考空間。作為入門(mén)的編程學(xué)習(xí)者,獨(dú)立思考能力和動(dòng)手編程能力都是至關(guān)重要的。在此,希望大家學(xué)習(xí)愉快,共同進(jìn)步。
自定義控件之xib方式
-
xib與storyboard
- 共同點(diǎn):
- 都用來(lái)描述軟件界面
- 都用Interface Builder工具來(lái)編輯
- 本質(zhì)都是轉(zhuǎn)換成代碼去創(chuàng)建控件
- 不同點(diǎn):
- Xib是輕量級(jí)的,用來(lái)描述局部的UI界面
- Storyboard是重量級(jí)的,用來(lái)描述整個(gè)軟件的多個(gè)界面,并且能展示多個(gè)界面之間的跳轉(zhuǎn)關(guān)系
- 共同點(diǎn):
-
Xib的加載方式
- 方式一:通過(guò)
mainBundelloadNibNamed:加載
- 方式一:通過(guò)
NSArray *views = [[NSBundle mainBundle] loadNibNamed:@"xib文件名" owner:nil options:nil]`
- 方式二:通過(guò)`UINib` `nibWithNibName`加載
UINib *nib = [UINib nibWithNibName:@"xib文件名" bundle:nil];
NSArray *views = [nib instantiateWithOwner:nil options:nil];
-
通過(guò)xib創(chuàng)建自定義控件步驟:
- 新建一個(gè)繼承
UIView的類(lèi) - 新建一個(gè)xib文件(xib的文件名最好跟控件類(lèi)名一樣)
- 添加子控件、設(shè)置子控件屬性
- 修改最外面那個(gè)控件的class為控件類(lèi)名
- 將子控件進(jìn)行連線
- 提供模型屬性,重寫(xiě)模型的set方法
- 在set方法中給子控件設(shè)置數(shù)據(jù)
- 新建一個(gè)繼承
示例代碼:
- (void)viewDidLoad {
//1.通過(guò)mainbundel獲取xib文件,返回組件數(shù)組
NSArray * viewArr = [[NSBundle mainBundle] loadNibNamed:@"CYXView" owner:nil options:nil];
//2.取出數(shù)組中需要的控件
CYXView * myView = (CYXView *)[viewArr lastObject];
//3.設(shè)置控件的Frame
myView.frame = CGRectMake(100, 100, 10, 200);
//4.控件添加到self.View中
[self.view addSubview:myView];
}
-
補(bǔ)充:
-
initWithcoder- 只要是從storyboard/xib中加載就會(huì)調(diào)用這個(gè)方法;
這個(gè)方法一般是初始化的操作
- 只要是從storyboard/xib中加載就會(huì)調(diào)用這個(gè)方法;
-
awakeFromNib-
storyboard/xib中加載完畢的時(shí)候調(diào)用,想做一些在xib加載完畢的操作,就在這個(gè)方法中操作(建議在這個(gè)方法中寫(xiě)初始化代碼)
-
-
自定義控件之純代碼方式
-
何為自定義控件?
- 繼承自系統(tǒng)自帶的控件,寫(xiě)一個(gè)屬于自己的控件
目的:封裝控件內(nèi)部的細(xì)節(jié)
-
為什么要封裝?
- 封裝的話,下次直接將封裝好的類(lèi),直接拿去使用
封裝以后,沒(méi)有重復(fù)代碼
- 封裝的話,下次直接將封裝好的類(lèi),直接拿去使用
-
自定義控件封裝步驟:
- 創(chuàng)建一個(gè)自定義控件,建議直接繼承自UIView,也可以繼承自其他組件
-
封裝的用途
- 以后需要封裝一些框架給外界使用的時(shí)候
對(duì)于項(xiàng)目擴(kuò)展性大大提高
- 以后需要封裝一些框架給外界使用的時(shí)候
-
示例代碼思路:
-
在新建的
CYXShopView視圖類(lèi)(View)中代碼思路如下- 1.定義子控件。在
init方法內(nèi)只管控件內(nèi)部的創(chuàng)建,但不管frame的初始化,因?yàn)橥饨缯{(diào)用的init方法不一定馬上給frame賦值,所以第一次init是frame的值可能為nil - 2.定義位置尺寸(Frame)。重寫(xiě)系統(tǒng)的
-(void)layoutSubviews方法,這個(gè)方法方法專(zhuān)門(mén)用來(lái)布局子控件,一般在這里設(shè)置子控件的frame,當(dāng)控件本身的尺寸發(fā)生改變的時(shí)候,系統(tǒng)會(huì)自動(dòng)調(diào)用這個(gè)方法。重寫(xiě)此方法內(nèi)一定要調(diào)用[super layoutSubviews] - 3.設(shè)置數(shù)據(jù)。提供一個(gè)模型屬性,重寫(xiě)模型屬性的set方法,在set方法中取出模型屬性,給對(duì)應(yīng)的子控件賦值
- 1.定義子控件。在
在自定義控件內(nèi)還可以添加其他更方便的初始化方法,可以參照apple官方的
UIView等主要控件,還可以更高層次的封裝,這個(gè)等以后再談及。
-
//重寫(xiě)-(instancetype)initWithFrame:(CGRect)frame方法
//init方法內(nèi)部會(huì)自動(dòng)調(diào)用-(instancetype)initWithFrame:(CGRect)frame 方法,因此建議寫(xiě)這個(gè)方法,用于替代-(instancetype)init 方法
-(instancetype)initWithFrame:(CGRect)frame{
if (self = [super init]) {
//添加圖片
UIImageView * iconView = [[UIImageView alloc]init];
iconView.backgroundColor = [UIColor grayColor];
[self addSubview:iconView];
//添加文字
UILabel * name = [[UILabel alloc]init];
name.backgroundColor = [UIColor greenColor];
name.font = [UIFont systemFontOfSize:15];
name.textAlignment = NSTextAlignmentCenter;
[self addSubview:name];
}
return self;
}
/**
* 這個(gè)方法專(zhuān)門(mén)用來(lái)布局子控件,一般在這里設(shè)置子控件的frame
* 當(dāng)控件本身的尺寸發(fā)生改變的時(shí)候,系統(tǒng)會(huì)自動(dòng)調(diào)用這個(gè)方
*/
-(void)layoutSubviews{
// 一定要調(diào)用super方法
[super layoutSubviews];
CGFloat shopW = self.frame.size.width;
CGFloat shopH = self.frame.size.height;
self.iconView.frame = CGRectMake(0, 0, shopW, shopW);
self.name.frame = CGRectMake(0, shopW, shopW, shopH-shopW);
}
-(void)setShop:(CYXShop *)shop{
//賦值
_shop = shop;
self.name.text = self.shop.name;
self.iconView.image = [UIImage imageNamed:self.shop.icon];
}
- 補(bǔ)充:
-
init和initWithFrame(一般在使用代碼創(chuàng)建的時(shí)候調(diào)用- 在調(diào)用
init的時(shí)候,系統(tǒng)會(huì)默認(rèn)調(diào)用一次initWithFrame;但在調(diào)用initWithFrame不會(huì)調(diào)用init;所以一般初始化自己的子控件一般都是放在initWithFrame
- 在調(diào)用
-
給封裝View設(shè)置數(shù)據(jù)的幾種方式
(1)直接將屬性暴漏在.h文件中:不好,影響封裝性,不應(yīng)該將自己的子控件暴漏在頭文件中
(2)提供一個(gè)初始化方法
-
(3)根據(jù)tag設(shè)置子控件數(shù)據(jù)
- 因?yàn)樽涌丶^少,所以設(shè)置比較方便。
- 控制器做的的太多了
(4)提供一個(gè)設(shè)置模型的方法,將模型傳遞過(guò)去(直接傳遞一個(gè)模型對(duì)象給View自己設(shè)置值)
(5)提供一個(gè)屬性,直接使用點(diǎn)語(yǔ)法賦值(最終采取的方法)