ios开发瀑布流框架的封装
一:瀑布流框架封裝的實(shí)現(xiàn)思路:此瀑布流框架的封裝仿照tableView的底層實(shí)現(xiàn),1:每個(gè)cell的frame的設(shè)置都是找出每列的最大y值,比較每列的最大y值,將下一個(gè)cell放在最大y值最小的那一列,并更新最大y值,繼續(xù)比較設(shè)置frame。2:還涉及了類似于tableView緩存池的處理 ?瀑布流效果如圖:
二:封裝代碼:
1:瀑布流控件的view封裝:
1 // 使用瀑布流形式展示內(nèi)容的控件 2 3 #import <UIKit/UIKit.h> 4 5 typedef enum { 6 HMWaterflowViewMarginTypeTop, 7 HMWaterflowViewMarginTypeBottom, 8 HMWaterflowViewMarginTypeLeft, 9 HMWaterflowViewMarginTypeRight, 10 HMWaterflowViewMarginTypeColumn, // 每一列 11 HMWaterflowViewMarginTypeRow, // 每一行 12 } HMWaterflowViewMarginType; 13 14 @class HMWaterflowView, HMWaterflowViewCell; 15 16 /** 17 * 數(shù)據(jù)源方法 18 */ 19 @protocol HMWaterflowViewDataSource <NSObject> 20 @required 21 /** 22 * 一共有多少個(gè)數(shù)據(jù) 23 */ 24 - (NSUInteger)numberOfCellsInWaterflowView:(HMWaterflowView *)waterflowView; 25 /** 26 * 返回index位置對(duì)應(yīng)的cell 27 */ 28 - (HMWaterflowViewCell *)waterflowView:(HMWaterflowView *)waterflowView cellAtIndex:(NSUInteger)index; 29 30 @optional 31 /** 32 * 一共有多少列 33 */ 34 - (NSUInteger)numberOfColumnsInWaterflowView:(HMWaterflowView *)waterflowView; 35 @end 36 37 /** 38 * 代理方法 39 */ 40 @protocol HMWaterflowViewDelegate <UIScrollViewDelegate> 41 @optional 42 /** 43 * 第index位置cell對(duì)應(yīng)的高度 44 */ 45 - (CGFloat)waterflowView:(HMWaterflowView *)waterflowView heightAtIndex:(NSUInteger)index; 46 /** 47 * 選中第index位置的cell 48 */ 49 - (void)waterflowView:(HMWaterflowView *)waterflowView didSelectAtIndex:(NSUInteger)index; 50 /** 51 * 返回間距 52 */ 53 - (CGFloat)waterflowView:(HMWaterflowView *)waterflowView marginForType:(HMWaterflowViewMarginType)type; 54 @end 55 56 /** 57 * 瀑布流控件 58 */ 59 @interface HMWaterflowView : UIScrollView 60 /** 61 * 數(shù)據(jù)源 62 */ 63 @property (nonatomic, weak) id<HMWaterflowViewDataSource> dataSource; 64 /** 65 * 代理 66 */ 67 @property (nonatomic, weak) id<HMWaterflowViewDelegate> delegate; 68 69 /** 70 * 刷新數(shù)據(jù)(只要調(diào)用這個(gè)方法,會(huì)重新向數(shù)據(jù)源和代理發(fā)送請(qǐng)求,請(qǐng)求數(shù)據(jù)) 71 */ 72 - (void)reloadData; 73 74 /** 75 * cell的寬度 76 */ 77 - (CGFloat)cellWidth; 78 79 /** 80 * 根據(jù)標(biāo)識(shí)去緩存池查找可循環(huán)利用的cell 81 */ 82 - (id)dequeueReusableCellWithIdentifier:(NSString *)identifier; 83 @end思路分析:1:仿照tableView來(lái)設(shè)置dataSource 和 delegate 兩個(gè)代理:waterFlow的dataSource代理方法中仿照tableView的dataSource代理方法,@required 必須實(shí)現(xiàn)的是,1:一共有多少個(gè)cell,- (NSUInteger)numberOfCellsInWaterflowView:(HMWaterflowView *)waterflowView ,2:根據(jù)cell的index返回每一個(gè)cell,- (HMWaterflowViewCell *)waterflowView:(HMWaterflowView *)waterflowView cellAtIndex:(NSUInteger)index;其中HMWaterflowViewCell就為每一個(gè)單元的cell,自定義HMWaterflowViewCell繼承于UIView 3:@optional 方法為,一共返回多少列,如果沒(méi)有實(shí)現(xiàn)此方法則返回默認(rèn)的列數(shù) 2:在waterFlow的delegate方法中,都為@optional,并仿照tableView提供,1:根據(jù)index返回每個(gè)cell的行高 ?- (CGFloat)waterflowView:(HMWaterflowView *)waterflowView heightAtIndex:(NSUInteger)index;2:點(diǎn)擊index處的cell的方法:- (void)waterflowView:(HMWaterflowView *)waterflowView didSelectAtIndex:(NSUInteger)index; 3:返回整個(gè)瀑布流的間距值,若不返回,則會(huì)有默認(rèn)值,上下左右,行間距,列間距,根據(jù)上下左右行列不同的類型返回不同的高度,將這幾個(gè)不同的類型定義成枚舉值,將枚舉傳過(guò)去,外界可利用switch根據(jù)不同類型,返回不同的間距(類似于按鈕回調(diào)的枚舉tag)
2:以屬性設(shè)置兩個(gè)代理:設(shè)置delegate時(shí),會(huì)有警告,因?yàn)槠俨剂骺丶^承的是UIScroll,則繼承了UIScroll在.h聲明的屬性和方法,此delegate會(huì)覆蓋掉scrollView的滾動(dòng)視圖的代理,所以會(huì)有警告,解決辦法是,讓瀑布流控件的代理協(xié)議再遵守UISCrollViewDelegate,則在外部只要遵守了瀑布流的代理,也就遵守了UIScroll的滾動(dòng)代理,所以以屬性設(shè)置瀑布流代理后,外部遵守協(xié)議,設(shè)置代理,則其就可以調(diào)用UIscroll的滾動(dòng)代理方法了
3:仿照tableView并提供刷新表格,和緩存池根據(jù)重用標(biāo)識(shí)取cell的方法,- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier;其中id 和 instanceType的區(qū)別:1:id 修飾非關(guān)聯(lián)返回類型 ,可做參數(shù),也可以做返回值 而instanceType為關(guān)聯(lián)返回類型,返回該方法所在類的類型,并且只能做返回值,一般以alloc。autorelease,retain開(kāi)頭的方法用id 2:用instanceType相對(duì)id來(lái)說(shuō),能幫助編譯器快速確定返回值類型。
2:瀑布流的內(nèi)部核心封裝代碼:
1 #import "HMWaterflowView.h" 2 #import "HMWaterflowViewCell.h" 3 4 #define HMWaterflowViewDefaultCellH 70 5 #define HMWaterflowViewDefaultMargin 8 6 #define HMWaterflowViewDefaultNumberOfColumns 3 7 8 @interface HMWaterflowView() 9 /** 10 * 所有cell的frame數(shù)據(jù) 11 */ 12 @property (nonatomic, strong) NSMutableArray *cellFrames; 13 /** 14 * 正在展示的cell 15 */ 16 @property (nonatomic, strong) NSMutableDictionary *displayingCells; 17 /** 18 * 緩存池(用Set,存放離開(kāi)屏幕的cell) 19 */ 20 @property (nonatomic, strong) NSMutableSet *reusableCells; 21 @end 22 23 @implementation HMWaterflowView 24 25 #pragma mark - 初始化 26 - (NSMutableArray *)cellFrames 27 { 28 if (_cellFrames == nil) { 29 self.cellFrames = [NSMutableArray array]; 30 } 31 return _cellFrames; 32 } 33 34 - (NSMutableDictionary *)displayingCells 35 { 36 if (_displayingCells == nil) { 37 self.displayingCells = [NSMutableDictionary dictionary]; 38 } 39 return _displayingCells; 40 } 41 42 - (NSMutableSet *)reusableCells 43 { 44 if (_reusableCells == nil) { 45 self.reusableCells = [NSMutableSet set]; 46 } 47 return _reusableCells; 48 } 49 50 - (id)initWithFrame:(CGRect)frame 51 { 52 self = [super initWithFrame:frame]; 53 if (self) { 54 55 } 56 return self; 57 } 58 59 - (void)willMoveToSuperview:(UIView *)newSuperview 60 { 61 [self reloadData]; 62 } 63 64 #pragma mark - 公共接口 65 /** 66 * cell的寬度 67 */ 68 - (CGFloat)cellWidth 69 { 70 // 總列數(shù) 71 int numberOfColumns = [self numberOfColumns]; 72 CGFloat leftM = [self marginForType:HMWaterflowViewMarginTypeLeft]; 73 CGFloat rightM = [self marginForType:HMWaterflowViewMarginTypeRight]; 74 CGFloat columnM = [self marginForType:HMWaterflowViewMarginTypeColumn]; 75 return (self.bounds.size.width - leftM - rightM - (numberOfColumns - 1) * columnM) / numberOfColumns; 76 } 77 78 /** 79 * 刷新數(shù)據(jù) 80 */ 81 - (void)reloadData 82 { 83 // 清空之前的所有數(shù)據(jù) 84 // 移除正在正在顯示cell 85 [self.displayingCells.allValues makeObjectsPerformSelector:@selector(removeFromSuperview)]; 86 [self.displayingCells removeAllObjects]; 87 [self.cellFrames removeAllObjects]; 88 [self.reusableCells removeAllObjects]; 89 90 // cell的總數(shù) 91 int numberOfCells = [self.dataSource numberOfCellsInWaterflowView:self]; 92 93 // 總列數(shù) 94 int numberOfColumns = [self numberOfColumns]; 95 96 // 間距 97 CGFloat topM = [self marginForType:HMWaterflowViewMarginTypeTop]; 98 CGFloat bottomM = [self marginForType:HMWaterflowViewMarginTypeBottom]; 99 CGFloat leftM = [self marginForType:HMWaterflowViewMarginTypeLeft]; 100 CGFloat columnM = [self marginForType:HMWaterflowViewMarginTypeColumn]; 101 CGFloat rowM = [self marginForType:HMWaterflowViewMarginTypeRow]; 102 103 // cell的寬度 104 CGFloat cellW = [self cellWidth]; 105 106 // 用一個(gè)C語(yǔ)言數(shù)組存放所有列的最大Y值 107 CGFloat maxYOfColumns[numberOfColumns]; 108 for (int i = 0; i<numberOfColumns; i++) { 109 maxYOfColumns[i] = 0.0; 110 } 111 112 // 計(jì)算所有cell的frame 113 for (int i = 0; i<numberOfCells; i++) { 114 // cell處在第幾列(最短的一列) 115 NSUInteger cellColumn = 0; 116 // cell所處那列的最大Y值(最短那一列的最大Y值) 117 CGFloat maxYOfCellColumn = maxYOfColumns[cellColumn]; 118 // 求出最短的一列 119 for (int j = 1; j<numberOfColumns; j++) { 120 if (maxYOfColumns[j] < maxYOfCellColumn) { 121 cellColumn = j; 122 maxYOfCellColumn = maxYOfColumns[j]; 123 } 124 } 125 126 // 詢問(wèn)代理i位置的高度 127 CGFloat cellH = [self heightAtIndex:i]; 128 129 // cell的位置 130 CGFloat cellX = leftM + cellColumn * (cellW + columnM); 131 CGFloat cellY = 0; 132 if (maxYOfCellColumn == 0.0) { // 首行 133 cellY = topM; 134 } else { 135 cellY = maxYOfCellColumn + rowM; 136 } 137 138 // 添加frame到數(shù)組中 139 CGRect cellFrame = CGRectMake(cellX, cellY, cellW, cellH); 140 [self.cellFrames addObject:[NSValue valueWithCGRect:cellFrame]]; 141 142 // 更新最短那一列的最大Y值 143 maxYOfColumns[cellColumn] = CGRectGetMaxY(cellFrame); 144 } 145 146 // 設(shè)置contentSize 147 CGFloat contentH = maxYOfColumns[0]; 148 for (int j = 1; j<numberOfColumns; j++) { 149 if (maxYOfColumns[j] > contentH) { 150 contentH = maxYOfColumns[j]; 151 } 152 } 153 contentH += bottomM; 154 self.contentSize = CGSizeMake(0, contentH); 155 } 156 157 /** 158 * 當(dāng)UIScrollView滾動(dòng)的時(shí)候也會(huì)調(diào)用這個(gè)方法 159 */ 160 - (void)layoutSubviews 161 { 162 [super layoutSubviews]; 163 164 // 向數(shù)據(jù)源索要對(duì)應(yīng)位置的cell 165 NSUInteger numberOfCells = self.cellFrames.count; 166 for (int i = 0; i<numberOfCells; i++) { 167 // 取出i位置的frame 168 CGRect cellFrame = [self.cellFrames[i] CGRectValue]; 169 170 // 優(yōu)先從字典中取出i位置的cell 171 HMWaterflowViewCell *cell = self.displayingCells[@(i)]; 172 173 // 判斷i位置對(duì)應(yīng)的frame在不在屏幕上(能否看見(jiàn)) 174 if ([self isInScreen:cellFrame]) {// 在屏幕上 175 if (cell == nil) { 176 cell = [self.dataSource waterflowView:self cellAtIndex:i]; 177 cell.frame = cellFrame; 178 [self addSubview:cell]; 179 180 // 存放到字典中 181 self.displayingCells[@(i)] = cell; 182 } 183 } else { // 不在屏幕上 184 if (cell) { 185 // 從scrollView和字典中移除 186 [cell removeFromSuperview]; 187 [self.displayingCells removeObjectForKey:@(i)]; 188 189 // 存放進(jìn)緩存池 190 [self.reusableCells addObject:cell]; 191 } 192 } 193 } 194 } 195 196 - (id)dequeueReusableCellWithIdentifier:(NSString *)identifier 197 { 198 __block HMWaterflowViewCell *reusableCell = nil; 199 200 [self.reusableCells enumerateObjectsUsingBlock:^(HMWaterflowViewCell *cell, BOOL *stop) { 201 if ([cell.identifier isEqualToString:identifier]) { 202 reusableCell = cell; 203 *stop = YES; 204 } 205 }]; 206 207 if (reusableCell) { // 從緩存池中移除 208 [self.reusableCells removeObject:reusableCell]; 209 } 210 return reusableCell; 211 } 212 213 #pragma mark - 私有方法 214 /** 215 * 判斷一個(gè)frame有無(wú)顯示在屏幕上 216 */ 217 - (BOOL)isInScreen:(CGRect)frame 218 { 219 return (CGRectGetMaxY(frame) > self.contentOffset.y) && 220 (CGRectGetMinY(frame) < self.contentOffset.y + self.bounds.size.height); 221 } 222 223 /** 224 * 間距 225 */ 226 - (CGFloat)marginForType:(HMWaterflowViewMarginType)type 227 { 228 if ([self.delegate respondsToSelector:@selector(waterflowView:marginForType:)]) { 229 return [self.delegate waterflowView:self marginForType:type]; 230 } else { 231 return HMWaterflowViewDefaultMargin; 232 } 233 } 234 /** 235 * 總列數(shù) 236 */ 237 - (NSUInteger)numberOfColumns 238 { 239 if ([self.dataSource respondsToSelector:@selector(numberOfColumnsInWaterflowView:)]) { 240 return [self.dataSource numberOfColumnsInWaterflowView:self]; 241 } else { 242 return HMWaterflowViewDefaultNumberOfColumns; 243 } 244 } 245 /** 246 * index位置對(duì)應(yīng)的高度 247 */ 248 - (CGFloat)heightAtIndex:(NSUInteger)index 249 { 250 if ([self.delegate respondsToSelector:@selector(waterflowView:heightAtIndex:)]) { 251 return [self.delegate waterflowView:self heightAtIndex:index]; 252 } else { 253 return HMWaterflowViewDefaultCellH; 254 } 255 } 256 257 #pragma mark - 事件處理 258 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 259 { 260 if (![self.delegate respondsToSelector:@selector(waterflowView:didSelectAtIndex:)]) return; 261 262 // 獲得觸摸點(diǎn) 263 UITouch *touch = [touches anyObject]; 264 // CGPoint point = [touch locationInView:touch.view]; 265 CGPoint point = [touch locationInView:self]; 266 267 __block NSNumber *selectIndex = nil; 268 [self.displayingCells enumerateKeysAndObjectsUsingBlock:^(id key, HMWaterflowViewCell *cell, BOOL *stop) { 269 if (CGRectContainsPoint(cell.frame, point)) { 270 selectIndex = key; 271 *stop = YES; 272 } 273 }]; 274 275 if (selectIndex) { 276 [self.delegate waterflowView:self didSelectAtIndex:selectIndex.unsignedIntegerValue]; 277 } 278 } 279 280 @end思路分析:1:瀑布流的核心代碼的封裝也是仿照tableView的底層實(shí)現(xiàn):在tableView第一次加載的時(shí)候會(huì)首先調(diào)用一次刷新數(shù)據(jù)的方法,在下列方法中實(shí)現(xiàn):
- (void)willMoveToSuperview:(UIView *)newSuperview{[self reloadData];},此方法willMoveToSuperview,是子view即將添加到superView時(shí)會(huì)調(diào)用一次。調(diào)用[self reloadData],模擬tableView第一次刷新表格 2:基本實(shí)現(xiàn)思路是,在reloadData方法中設(shè)置每一個(gè)cell的frame,存放到大數(shù)組中,再在layoutSubView里設(shè)置每一個(gè)view的frame。
2:在reloadData方法中,1:每執(zhí)行一次reloadData方法,都要將原來(lái)的數(shù)據(jù)清空,來(lái)展示新的cell。其中self.displayingCells為正在顯示的cell的緩存字典,key值為每一個(gè)index,value為每一個(gè)index對(duì)應(yīng)的正在顯示的cell(dic.allKeys,dic.allValues,分別獲得字典的所有的key值和value值得到一個(gè)數(shù)組,enum遍歷字典的時(shí)候,分別可得到字典的key值和value值)。2:在清空數(shù)據(jù)時(shí),緩存字典,讓字典中每一個(gè)正在顯示的cell從父視圖上移除,并清空緩存字典,緩存池,還有裝有frame的數(shù)組,其中數(shù)組里有一個(gè)方法是遍歷每個(gè)元素讓每個(gè)元素都去執(zhí)行某個(gè)方法[self.displayingCells.allValues makeObjectsPerformSelector:@selector(removeFromSuperview)]; 2:在reloadData中最主要的就是要求出每個(gè)cell的xy寬高,其中高度需要詢問(wèn)代理,若實(shí)現(xiàn)了代理方法,則根據(jù)服務(wù)器返回圖片的寬高,按比例計(jì)算出相應(yīng)的高度并返回。要想設(shè)置每個(gè)cell的frame,調(diào)用數(shù)據(jù)源方法,返回總的cell的個(gè)數(shù),for循環(huán)遍歷每個(gè)cell,因?yàn)樵O(shè)置frame,要從最大y值最小的那列開(kāi)始設(shè)置,所以在for循環(huán)遍歷每一個(gè)cell的時(shí)候,首先應(yīng)找出最小y值的那一列,和最小y值。定義數(shù)組存放每一列的最大的y值,因?yàn)槠錇榛緮?shù)據(jù)類型,所以用C語(yǔ)言數(shù)組存放,OC數(shù)組只能存放對(duì)象。先調(diào)用代理方法返回列數(shù),若沒(méi)有實(shí)現(xiàn)代理方法,則默認(rèn)返回的而是3列,定義C語(yǔ)言的數(shù)組,定義數(shù)組元素個(gè)數(shù)為numberOfColumns列數(shù)的數(shù)組,且數(shù)組中元素的基本類型都為CGFloat類型。并對(duì)數(shù)組中的元素初始化,遍歷數(shù)組,取出每個(gè)元素,賦值為0.0,float類型
??CGFloat maxYOfColumns[numberOfColumns];
? ? for (int i = 0; i<numberOfColumns; i++) {
? ? ? ? maxYOfColumns[i] = 0.0;
? ? }
3:找出最小y值所在的列號(hào),并記錄此列下最大的y值。先假設(shè)最小的y值的列號(hào)是第0列,則最小y值列號(hào)下的最大的y值就為從C語(yǔ)言數(shù)組中根據(jù)列號(hào)取出的該列的最大y值,再for循環(huán)遍歷C語(yǔ)言數(shù)組,從列號(hào)為1開(kāi)始遍歷,做判斷,從列號(hào)為1開(kāi)始從數(shù)組中取出的最大y值還比定義的最大y值還小,則此時(shí)記錄下最小的y值的列號(hào),和最小y值列號(hào)下的最大y值。直到找到最小y值的列號(hào),此時(shí),設(shè)置frame就從最小y值的列號(hào)處開(kāi)始設(shè)置。
4:找到最小y值所在的列號(hào)后,開(kāi)始設(shè)置cell的frame,寬度 = 屏幕寬度 - 左右間距 - (總列數(shù) -1)*列間距,都可以求出,屏幕的高度,調(diào)用代理根據(jù)index返回該index處的cell的高度,(瀑布流圖片的寬高都為后臺(tái)服務(wù)器返回),若實(shí)現(xiàn)了代理高度的方法,則返回高度時(shí),應(yīng)該根據(jù)服務(wù)器返回圖片高度的比例計(jì)算出。若沒(méi)實(shí)現(xiàn)代理方法則返回默認(rèn)的高度。?詢問(wèn)代理i位置的高度?CGFloat cellH = [self heightAtIndex:i];X值的計(jì)算:計(jì)算x值和cell所在的列號(hào)有關(guān),?CGFloat cellX = leftM + cellColumn * (cellW + columnM);Y值計(jì)算:和是否是首行有關(guān),若是在首行,則y值為頂部間距,若不在首行,則y值為該列的最大y值加上一個(gè)行間距的值,是否是首行的判斷,則判斷C語(yǔ)言數(shù)組中每一列對(duì)應(yīng)的最大y值,若為0,則在首行,若不為0,則不在首行,此時(shí)可以設(shè)置cell的frame
5:將設(shè)置好的cell的frame(結(jié)構(gòu)體類型,非對(duì)象)封裝成OC對(duì)象,存放到數(shù)組中。?CGRect cellFrame = CGRectMake(cellX, cellY, cellW, cellH);?[self.cellFrames addObject:[NSValue valueWithCGRect:cellFrame]];
6:還要更新C語(yǔ)言數(shù)組中設(shè)置frame的所在列的最大y值,以便下次循環(huán)計(jì)算:maxYOfColumns[cellColumn] = CGRectGetMaxY(cellFrame);
7:在設(shè)置完所有的frame后,要根據(jù)C語(yǔ)言數(shù)組中最大的y值,計(jì)算scrollView的contentSize,否則scrollView將不會(huì)滾動(dòng)。如何找出最大的y值?先定義第0列為最大y值,將最大的y值從數(shù)組中取出,在for循環(huán)遍歷C語(yǔ)言數(shù)組,j從1開(kāi)始,將數(shù)組中的每一列最大y值取出比較,若比這個(gè)最大的還大,則記錄下來(lái),最后計(jì)算contentSize為最大y值加一個(gè)底部間距
?CGFloat contentH = maxYOfColumns[0];
? ? for (int j = 1; j<numberOfColumns; j++) {
? ? ? ? if (maxYOfColumns[j] > contentH) {
? ? ? ? ? ? contentH = maxYOfColumns[j];
? ? ? ? }
? ? }
? ? contentH += bottomM;
? ? self.contentSize = CGSizeMake(0, contentH);
?
3:layoutSubView中設(shè)置每一個(gè)cell的frame:1:遍歷存放cell所有frame的數(shù)組,取出每一個(gè)frame,CGRect cellFrame = [self.cellFrames[i] CGRectValue];首先先判斷是否在屏幕上,如果不在屏幕上,則將其cell從父視圖上移除,并且從緩存字典中移除,并加入到緩存池,NSMutableSet 所定義的集合中,同數(shù)組的用法是相同,存放對(duì)象,但數(shù)組是有序的,NSMutableSet是無(wú)序的。如果在屏幕上顯示,則證明已經(jīng)計(jì)算好frame,則優(yōu)先從緩存字典中根據(jù)索引取出cell。判斷取出的cell是否存在,不存在,則調(diào)用數(shù)據(jù)源方法,從緩存池中取或是自行創(chuàng)建,返回一個(gè)cell,設(shè)置frame,添加到scrollView上。并將新創(chuàng)建的cell存入緩存字典中。2:如何判斷是否在屏幕上,傳遞frame,根據(jù)frame判斷是否在屏幕上
- (BOOL)isInScreen:(CGRect)frame
{
? ? return (CGRectGetMaxY(frame) > self.contentOffset.y) &&
? ? (CGRectGetMinY(frame) < self.contentOffset.y + self.bounds.size.height);
}
4:根據(jù)重用標(biāo)識(shí)從緩存池中取數(shù)據(jù):遍歷集合,得到每一個(gè)cell,做條件過(guò)濾,判斷如果cell的重用標(biāo)識(shí)符與傳入的標(biāo)識(shí)符相等,則賦值cell,并停止遍歷,在block內(nèi)部若是想賦值外部變量,則用__block修飾外部的變量,最后再判斷cell如果存在從緩存池中刪除,若是不刪除重用的cell,則其不到重用的作用,內(nèi)存會(huì)被撐爆.
5:cell的點(diǎn)擊事件:1:若是想實(shí)現(xiàn)點(diǎn)擊事件:1:繼承UIControl的addTarget ?,touch或是valueChanged 2;添加手勢(shì)監(jiān)聽(tīng)器,要開(kāi)啟用戶交互權(quán)限(如lable,iamgeView)3:實(shí)現(xiàn)touchBeagn,touchEnd,touchCancle方法,其中的touchBeagn剛開(kāi)始點(diǎn)擊的時(shí)候調(diào)用,touchEnd結(jié)束點(diǎn)擊的時(shí)候調(diào)用。2:cell的點(diǎn)擊采取實(shí)現(xiàn)touch方法,實(shí)現(xiàn)的是touchEnd,點(diǎn)擊結(jié)束時(shí)的方法。并實(shí)現(xiàn)UITouch的方法。3:首先做條件過(guò)濾,若沒(méi)有實(shí)現(xiàn)該代理方法,直接返回,若實(shí)現(xiàn)了代理方法,先獲得觸摸點(diǎn),?UITouch *touch = [touches anyObject];?CGPoint point = [touch locationInView:self];得到觸摸點(diǎn),若是第二個(gè)參數(shù)為cell則觸摸點(diǎn)的位置是相對(duì)cell來(lái)計(jì)算的,若是為self,則是針對(duì)整個(gè)瀑布流控件的frame來(lái)計(jì)算的。其中touch.view獲得的是觸摸的view,也就是cell 。目的是求出index,調(diào)用代理將index傳過(guò)去,所以遍歷緩存字典,得到key,value值,key為index,value為cell,再判斷所得觸摸點(diǎn)在不在cell上,調(diào)用CGRectContainsPoint(cell.frame, point),如果在,則賦值index,停止遍歷,再外部判斷index值是否存在,存在則調(diào)用代理執(zhí)行代理的點(diǎn)擊方法。@5或是@(3)兩個(gè)均為對(duì)象的表示形式,都為NSNumber類型。
7:自定義cell的封裝:
1 #import <UIKit/UIKit.h> 2 3 @interface HMWaterflowViewCell : UIView 4 @property (nonatomic, copy) NSString *identifier; 5 @end 1 #import "HMWaterflowViewCell.h" 2 3 @implementation HMWaterflowViewCell 4 5 - (id)initWithFrame:(CGRect)frame 6 { 7 self = [super initWithFrame:frame]; 8 if (self) { 9 // Initialization code 10 } 11 return self; 12 } 13 14 /* 15 // Only override drawRect: if you perform custom drawing. 16 // An empty implementation adversely affects performance during animation. 17 - (void)drawRect:(CGRect)rect 18 { 19 // Drawing code 20 } 21 */ 22 23 @end?
轉(zhuǎn)載于:https://www.cnblogs.com/cqb-learner/p/5733416.html
總結(jié)
以上是生活随笔為你收集整理的ios开发瀑布流框架的封装的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 设计模式之职责链模式
- 下一篇: FFmpeg学习1:视频解码