一、概述
1、對(duì)于經(jīng)常使用的控件或類,通常將其分裝為一個(gè)單獨(dú)的類來供外界使用,以此達(dá)到事半功倍的效果
2、由于分裝的類不依賴于其他的類,所以若要使用該類,可直接將該類拖進(jìn)項(xiàng)目文件即可
3、在進(jìn)行分裝的時(shí)候,通常需要用到代理設(shè)計(jì)模式
二、代理設(shè)計(jì)模式
1、代理設(shè)計(jì)模式的組成
客戶類(通常作為代理):通常委托這是角色來完成業(yè)務(wù)邏輯
真實(shí)角色:將客戶類的業(yè)務(wù)邏輯轉(zhuǎn)化為方法列表,即代理協(xié)議
代理協(xié)議:
- 定義了需要實(shí)現(xiàn)的業(yè)務(wù)邏輯
- 定義了一組方法列表,包括必須實(shí)現(xiàn)的方法或選擇實(shí)現(xiàn)的方法
- 代理協(xié)議是代理對(duì)象所要遵循一組規(guī)則
代理角色
- 若要作為代理,需要遵守代理協(xié)議,并且實(shí)現(xiàn)必須實(shí)現(xiàn)的代理方法
- 代理角色可以通過調(diào)用代理協(xié)議中的方法完成業(yè)務(wù)邏輯,也可以附加自己的操作
文字描述通常是抽象的,一下通過圖示來闡述代理設(shè)計(jì)模式
三、自定義布局類的封裝
1、業(yè)務(wù)邏輯
如圖
2、布局每個(gè)cell的業(yè)務(wù)邏輯
由于設(shè)置每個(gè)cell的布局屬性的業(yè)務(wù)邏輯較復(fù)雜,特附上如下思維導(dǎo)圖
3、封裝思路封裝需要根據(jù)客戶類業(yè)務(wù)邏輯需求來提供接口
1)、通過代理協(xié)議的可選實(shí)現(xiàn)的方法獲取的屬性值的屬性,需要設(shè)置默認(rèn)值
2)、未提供默認(rèn)值的且必須使用的屬性,需要通過必須實(shí)現(xiàn)的方法來獲得
3)、自定義布局提供的接口可選
- 列數(shù)
- 列之間的間距
- 行之間的間距
- 內(nèi)邊距
4)、自定義布局提供的接口必選
每個(gè)元素的高度,寬度可以通過列數(shù)和列間距計(jì)算得到
四、封裝步驟
設(shè)置代理協(xié)議,提供接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
//聲明lypwaterflowlayout為一個(gè)類 @ class lypwaterflowlayout; @protocol lypwaterflowlayoutdelegate <nsobject> //必須實(shí)現(xiàn)的方法 @required /**獲取瀑布流每個(gè)元素的高度*/ - (cgfloat)waterflowlayout:(lypwaterflowlayout *)waterflowlayout heightforitematindex:(nsinteger)index itemwith:(cgfloat)itemwith; //可選實(shí)現(xiàn)的方法 @optional /**獲取瀑布流的列數(shù)*/ - (nsinteger)columncountinwaterflowlayout:(lypwaterflowlayout *)waterflowlayout; /**獲取瀑布流列間距*/ - (cgfloat)columnmargininwaterflowlayout:(lypwaterflowlayout *)waterflowlayout; /**獲取瀑布流的行間距*/ - (cgfloat)rowmargininwaterflowlayout:(lypwaterflowlayout *)waterflowlayout; /**獲取瀑布流的內(nèi)邊距*/ - (uiedgeinsets)edgeinsetsinwaterflowlayout:(lypwaterflowlayout *)waterflowlayout; @end |
設(shè)置代理屬性
1
2
3
4
|
@interface lypwaterflowlayout : uicollectionviewlayout /**代理*/ @property (nonatomic, weak) id<lypwaterflowlayoutdelegate> delegate; @end |
設(shè)置通過可選代理方法獲取屬性值的屬性的默認(rèn)值
1
2
3
4
5
6
7
8
|
/**默認(rèn)的列數(shù)*/ static const nsinteger lypdefaultcolumncount = 3; /**默認(rèn)每一列之間的間距*/ static const cgfloat lypdefaultcolummargin = 10; /**默認(rèn)每一行之間的間距*/ static const cgfloat lypdefaultrowmargin = 10; /**默認(rèn)邊緣間距*/ static const uiedgeinsets lypdefaultedgeinsets = {10, 10, 10, 10}; |
設(shè)置通過可選代理方法獲取屬性值的屬性的訪問方式若代理提供屬性值,則忽略默認(rèn)值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
- (nsinteger)columncount { //判斷代理是否實(shí)現(xiàn)了獲取列數(shù)的可選方法 if ([self.delegate respondstoselector:@selector(columncountinwaterflowlayout:)]) { //實(shí)現(xiàn),返回通過代理設(shè)置的列數(shù) return [self.delegate columncountinwaterflowlayout:self]; } else { //為實(shí)現(xiàn),返回默認(rèn)的列數(shù) return lypdefaultcolumncount; } } |
注:其他屬性值的獲取與上述方法幾乎完全相同,不再贅述
設(shè)置布局
1)、設(shè)置需要的成員屬性
1
2
3
4
|
/**所有cell的布局屬性*/ @property (nonatomic, strong) nsmutablearray *attrsarray; /**所有列的當(dāng)前高度*/ @property (nonatomic, strong) nsmutablearray *columnheights; |
2)、通過懶加載的方式初始化成員屬性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/**--attrsarray--懶加載*/ - (nsmutablearray *)attrsarray { if (_attrsarray == nil) { _attrsarray = [nsmutablearray array]; } return _attrsarray; } /**--columnheights--懶加載*/ - (nsmutablearray *)columnheights { if (_columnheights == nil) { _columnheights = [nsmutablearray array]; } return _columnheights; } |
3)、初始化布局
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
|
- ( void )preparelayout { [super preparelayout]; /**清除之前跟布局相關(guān)的所有屬性,重新設(shè)置新的布局*/ //清除之前計(jì)算的所有列的高度 [self.columnheights removeallobjects]; //設(shè)置所有列的初始高度 for (nsinteger i = 0; i<self.columncount; i++) { self.columnheights[i] = @(self.edgeinsets.top); } //清除之前所有的布局屬性 [self.attrsarray removeallobjects]; /**開始創(chuàng)建每一個(gè)cell對(duì)應(yīng)的布局屬性*/ nsinteger count = [self.collectionview numberofitemsinsection:0]; for (nsinteger i = 0; i<count; i++) { nsindexpath *indexpath = [nsindexpath indexpathforitem:i insection:0]; //獲取indexpath位置cell對(duì)應(yīng)的布局屬性 uicollectionviewlayoutattributes *attrs = [self layoutattributesforitematindexpath:indexpath]; //將indexpath位置的cell的布局屬性添加到所有cell的布局屬性數(shù)組中 [self.attrsarray addobject:attrs]; } } |
4)、返回包含所有cell的布局屬性的數(shù)組
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
|
- (nullable nsarray<uicollectionviewlayoutattributes *> *)layoutattributesforelementsinrect:(cgrect)rect { return self.attrsarray; } 設(shè)置每一個(gè)cell的布局屬性 - (nullable uicollectionviewlayoutattributes *)layoutattributesforitematindexpath:(nonnull nsindexpath *)indexpath { //獲取indexpath位置的布局屬性 uicollectionviewlayoutattributes *attrs = [uicollectionviewlayoutattributes layoutattributesforcellwithindexpath:indexpath]; /**設(shè)置cell布局屬性的frame*/ /***確定cell的尺寸***/ //獲取collectionview的寬度 cgfloat collectionviewwidth = self.collectionview.frame.size.width; //cell寬度 cgfloat width = ((collectionviewwidth - self.edgeinsets.left - self.edgeinsets.right - (self.columncount - 1) * self.colummargin)) / self.columncount; //cell高度 cgfloat height = [self.delegate waterflowlayout:self heightforitematindex:indexpath.item itemwith:width]; /***設(shè)置cell的位置***/ nsinteger destcolumn = 0; cgfloat mincolumnheight = [self.columnheights[0] doublevalue]; for (nsinteger i = 1; i<self.columncount; i++) { cgfloat columnheight = [self.columnheights[i] doublevalue]; if (mincolumnheight > columnheight) { mincolumnheight = columnheight; destcolumn = i; } } //計(jì)算cell的位置 cgfloat x = self.edgeinsets.left + destcolumn * (width + self.colummargin); cgfloat y = mincolumnheight; //判斷是不是第一行 if (y != self.edgeinsets.top) { //若不是第一行,需要加上行間距 y += self.rowmargin; } /**給cell的布局屬性的frame賦值*/ attrs.frame = cgrectmake(x, y, width, height); //更新最短那列的高度 self.columnheights[destcolumn] = @(cgrectgetmaxy(attrs.frame)); /**返回indexpath位置的cell的布局屬性*/ return attrs; } |
5)、設(shè)置collectionview內(nèi)容的尺寸
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
- (cgsize)collectionviewcontentsize { //獲取最高的那一列的高度 cgfloat maxcolumnheight = [self.columnheights[0] doublevalue]; for (nsinteger i = 1; i<self.columncount; i++) { cgfloat columnheight = [self.columnheights[i] doublevalue]; if (maxcolumnheight < columnheight) { maxcolumnheight = columnheight; } } //返回collectionview的contentsize,高度為最高的高度加上一個(gè)行間距 return cgsizemake(0, maxcolumnheight + self.rowmargin); } |
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助。