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