ZLCollectionViewFlowLayout.m 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985
  1. //
  2. // ZLCollectionViewFlowLayout.m
  3. // ZLCollectionView
  4. //
  5. // Created by zhaoliang chen on 2017/6/22.
  6. // Copyright © 2017年 zhaoliang chen. All rights reserved.
  7. //
  8. #import "ZLCollectionViewFlowLayout.h"
  9. #import "ZLCollectionViewLayoutAttributes.h"
  10. #import "ZLCellFakeView.h"
  11. typedef NS_ENUM(NSUInteger, LewScrollDirction) {
  12. LewScrollDirctionStay,
  13. LewScrollDirctionToTop,
  14. LewScrollDirctionToEnd,
  15. };
  16. @interface ZLCollectionViewFlowLayout()
  17. <UIGestureRecognizerDelegate>
  18. //每个section的每一列的高度
  19. @property (nonatomic, retain) NSMutableArray *collectionHeightsArray;
  20. //存放每一个cell的属性
  21. @property (nonatomic, retain) NSMutableArray *attributesArray;
  22. //关于拖动的参数
  23. @property (nonatomic, strong) ZLCellFakeView *cellFakeView;
  24. @property (nonatomic, strong) UILongPressGestureRecognizer *longPress;
  25. @property (nonatomic, strong) UIPanGestureRecognizer *panGesture;
  26. @property (nonatomic, assign) CGPoint fakeCellCenter;
  27. @property (nonatomic, assign) CGPoint panTranslation;
  28. @property (nonatomic) LewScrollDirction continuousScrollDirection;
  29. @property (nonatomic, strong) CADisplayLink *displayLink;
  30. @end
  31. @implementation ZLCollectionViewFlowLayout
  32. #pragma mark - 初始化属性
  33. - (instancetype)init {
  34. self = [super init];
  35. if (self) {
  36. self.isFloor = YES;
  37. self.canDrag = NO;
  38. self.header_suspension = NO;
  39. self.layoutType = FillLayout;
  40. self.columnCount = 1;
  41. [self addObserver:self forKeyPath:@"collectionView" options:NSKeyValueObservingOptionNew context:nil];
  42. }
  43. return self;
  44. }
  45. #pragma mark - 当尺寸有所变化时,重新刷新
  46. - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
  47. return YES;
  48. }
  49. + (Class)layoutAttributesClass {
  50. return [ZLCollectionViewLayoutAttributes class];
  51. }
  52. - (void)dealloc {
  53. [self removeObserver:self forKeyPath:@"collectionView"];
  54. }
  55. - (void)prepareLayout {
  56. [super prepareLayout];
  57. CGFloat totalWidth = self.collectionView.frame.size.width;
  58. CGFloat x = 0;
  59. CGFloat y = 0;
  60. CGFloat headerH = 0;
  61. CGFloat footerH = 0;
  62. UIEdgeInsets edgeInsets = UIEdgeInsetsZero;
  63. CGFloat minimumLineSpacing = 0;
  64. CGFloat minimumInteritemSpacing = 0.0;
  65. NSUInteger sectionCount = [self.collectionView numberOfSections];
  66. _attributesArray = [NSMutableArray new];
  67. _collectionHeightsArray = [NSMutableArray arrayWithCapacity:sectionCount];
  68. for (int index= 0; index<sectionCount; index++) {
  69. NSUInteger itemCount = [self.collectionView numberOfItemsInSection:index];
  70. if (_delegate && [_delegate respondsToSelector:@selector(collectionView:layout:referenceSizeForHeaderInSection:)]) {
  71. headerH = [_delegate collectionView:self.collectionView layout:self referenceSizeForHeaderInSection:index].height;
  72. } else {
  73. headerH = self.headerReferenceSize.height;
  74. }
  75. if (_delegate && [_delegate respondsToSelector:@selector(collectionView:layout:referenceSizeForFooterInSection:)]) {
  76. footerH = [_delegate collectionView:self.collectionView layout:self referenceSizeForFooterInSection:index].height;
  77. } else {
  78. footerH = self.footerReferenceSize.height;
  79. }
  80. if (_delegate && [_delegate respondsToSelector:@selector(collectionView:layout:insetForSectionAtIndex:)]) {
  81. edgeInsets = [_delegate collectionView:self.collectionView layout:self insetForSectionAtIndex:index];
  82. } else {
  83. edgeInsets = self.sectionInset;
  84. }
  85. if (_delegate && [_delegate respondsToSelector:@selector(collectionView:layout:minimumLineSpacingForSectionAtIndex:)]) {
  86. minimumLineSpacing = [_delegate collectionView:self.collectionView layout:self minimumLineSpacingForSectionAtIndex:index];
  87. } else {
  88. minimumLineSpacing = self.minimumLineSpacing;
  89. }
  90. if (_delegate && [_delegate respondsToSelector:@selector(collectionView:layout:minimumInteritemSpacingForSectionAtIndex:)]) {
  91. minimumInteritemSpacing = [_delegate collectionView:self.collectionView layout:self minimumInteritemSpacingForSectionAtIndex:index];
  92. } else {
  93. minimumInteritemSpacing = self.minimumInteritemSpacing;
  94. }
  95. if (_delegate && [_delegate respondsToSelector:@selector(collectionView:layout:registerBackView:)]) {
  96. NSString* className = [_delegate collectionView:self.collectionView layout:self registerBackView:index];
  97. if (className != nil && className.length > 0) {
  98. NSAssert([[NSClassFromString(className) alloc]init]!=nil, @"代理collectionView:layout:registerBackView:里面必须返回有效的类名!");
  99. [self registerClass:NSClassFromString(className) forDecorationViewOfKind:className];
  100. } else {
  101. [self registerClass:[ZLCollectionReusableView class] forDecorationViewOfKind:@"ZLCollectionReusableView"];
  102. }
  103. } else {
  104. [self registerClass:[ZLCollectionReusableView class] forDecorationViewOfKind:@"ZLCollectionReusableView"];
  105. }
  106. x = edgeInsets.left;
  107. y = [self maxHeightWithSection:index];
  108. // 添加页首属性
  109. if (headerH > 0) {
  110. NSIndexPath *headerIndexPath = [NSIndexPath indexPathForItem:0 inSection:index];
  111. ZLCollectionViewLayoutAttributes* headerAttr = [ZLCollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader withIndexPath:headerIndexPath];
  112. headerAttr.frame = CGRectMake(0, y, self.collectionView.frame.size.width, headerH);
  113. [_attributesArray addObject:headerAttr];
  114. }
  115. y += headerH ;
  116. CGFloat itemStartY = y;
  117. CGFloat lastY = y;
  118. if (itemCount > 0) {
  119. y += edgeInsets.top;
  120. //ZLLayoutType layoutType = FillLayout;
  121. if (_delegate && [_delegate respondsToSelector:@selector(collectionView:layout:typeOfLayout:)]) {
  122. self.layoutType = [_delegate collectionView:self.collectionView layout:self typeOfLayout:index];
  123. }
  124. //NSInteger columnCount = 1;
  125. if (_delegate && [_delegate respondsToSelector:@selector(collectionView:layout:columnCountOfSection:)]) {
  126. self.columnCount = [_delegate collectionView:self.collectionView layout:self columnCountOfSection:index];
  127. }
  128. // 定义一个列高数组 记录每一列的总高度
  129. CGFloat *columnHeight = (CGFloat *) malloc(self.columnCount * sizeof(CGFloat));
  130. CGFloat itemWidth = 0.0;
  131. if (self.layoutType == ClosedLayout) {
  132. for (int i=0; i<self.columnCount; i++) {
  133. columnHeight[i] = y;
  134. }
  135. itemWidth = (totalWidth - edgeInsets.left - edgeInsets.right - minimumInteritemSpacing * (self.columnCount - 1)) / self.columnCount;
  136. }
  137. CGFloat maxYOfPercent = y;
  138. CGFloat maxYOfFill = y;
  139. NSMutableArray* arrayOfPercent = [NSMutableArray new]; //储存百分比布局的数组
  140. NSMutableArray* arrayOfFill = [NSMutableArray new]; //储存填充式布局的数组
  141. NSMutableArray* arrayOfAbsolute = [NSMutableArray new]; //储存绝对定位布局的数组
  142. for (int i=0; i<itemCount; i++) {
  143. NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:index];
  144. CGSize itemSize = CGSizeZero;
  145. if (_delegate && [_delegate respondsToSelector:@selector(collectionView:layout:sizeForItemAtIndexPath:)]) {
  146. itemSize = [_delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath];
  147. } else {
  148. itemSize = self.itemSize;
  149. }
  150. ZLCollectionViewLayoutAttributes *attributes = [ZLCollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
  151. NSInteger preRow = _attributesArray.count - 1;
  152. switch (self.layoutType) {
  153. #pragma mark 标签布局处理
  154. case LabelLayout: {
  155. //找上一个cell
  156. if(preRow >= 0){
  157. if(i > 0) {
  158. ZLCollectionViewLayoutAttributes *preAttr = _attributesArray[preRow];
  159. x = preAttr.frame.origin.x + preAttr.frame.size.width + minimumInteritemSpacing;
  160. if (x + itemSize.width > totalWidth - edgeInsets.right) {
  161. x = edgeInsets.left;
  162. y += itemSize.height + minimumLineSpacing;
  163. }
  164. }
  165. }
  166. attributes.frame = CGRectMake(x, y, itemSize.width, itemSize.height);
  167. }
  168. break;
  169. #pragma mark 列布局处理
  170. case ClosedLayout: {
  171. CGFloat max = CGFLOAT_MAX;
  172. NSInteger column = 0;
  173. for (int i = 0; i < self.columnCount; i++) {
  174. if (columnHeight[i] < max) {
  175. max = columnHeight[i];
  176. column = i;
  177. }
  178. }
  179. CGFloat itemX = edgeInsets.left + (itemWidth+minimumInteritemSpacing)*column;
  180. CGFloat itemY = columnHeight[column];
  181. attributes.frame = CGRectMake(itemX, itemY, itemWidth, itemSize.height);
  182. columnHeight[column] += (itemSize.height + minimumLineSpacing);
  183. }
  184. break;
  185. #pragma mark 百分比布局处理
  186. case PercentLayout: {
  187. CGFloat percent = 0.0f;
  188. if (_delegate && [_delegate respondsToSelector:@selector(collectionView:layout:percentOfRow:)]) {
  189. percent = [_delegate collectionView:self.collectionView layout:self percentOfRow:indexPath];
  190. } else {
  191. percent = 1;
  192. }
  193. if (percent > 1 || percent <= 0) {
  194. percent = 1;
  195. }
  196. if (arrayOfPercent.count > 0) {
  197. CGFloat totalPercent = 0;
  198. for (NSDictionary* dic in arrayOfPercent) {
  199. totalPercent += [dic[@"percent"] floatValue];
  200. }
  201. if ((totalPercent+percent) >= 1.0) {
  202. if ((totalPercent+percent) < 1.1) {
  203. //小于1.1就当成一行来计算
  204. //先添加进总的数组
  205. attributes.indexPath = indexPath;
  206. attributes.frame = CGRectMake(0, 0, itemSize.width, itemSize.height);
  207. //再添加进计算比例的数组
  208. [arrayOfPercent addObject:[NSMutableDictionary dictionaryWithDictionary:@{@"item":attributes,@"percent":[NSNumber numberWithFloat:percent],@"indexPath":indexPath}]];
  209. if ((totalPercent+percent) > 1) {
  210. NSMutableDictionary* lastDic = [NSMutableDictionary dictionaryWithDictionary:arrayOfPercent.lastObject];
  211. CGFloat lastPercent = 1.0;
  212. for (NSInteger i=0; i<arrayOfPercent.count-1; i++) {
  213. NSMutableDictionary* dic = arrayOfPercent[i];
  214. lastPercent -= [dic[@"percent"] floatValue];
  215. }
  216. lastDic[@"percent"] = [NSNumber numberWithFloat:lastPercent];
  217. [arrayOfPercent replaceObjectAtIndex:arrayOfPercent.count-1 withObject:lastDic];
  218. }
  219. CGFloat realWidth = totalWidth - edgeInsets.left - edgeInsets.right - (arrayOfPercent.count-1)*minimumInteritemSpacing;
  220. for (NSInteger i=0; i<arrayOfPercent.count; i++) {
  221. NSDictionary* dic = arrayOfPercent[i];
  222. ZLCollectionViewLayoutAttributes *newAttributes = dic[@"item"];
  223. CGFloat itemX = 0.0f;
  224. if (i==0) {
  225. itemX = edgeInsets.left;
  226. } else {
  227. ZLCollectionViewLayoutAttributes *preAttr = arrayOfPercent[i-1][@"item"];
  228. itemX = preAttr.frame.origin.x + preAttr.frame.size.width + minimumInteritemSpacing;
  229. }
  230. newAttributes.frame = CGRectMake(itemX, maxYOfPercent+minimumLineSpacing, realWidth*[dic[@"percent"] floatValue], newAttributes.frame.size.height);
  231. newAttributes.indexPath = dic[@"indexPath"];
  232. //if (![_attributesArray containsObject:newAttributes]) {
  233. [_attributesArray addObject:newAttributes];
  234. //}
  235. }
  236. for (NSInteger i=0; i<arrayOfPercent.count; i++) {
  237. NSDictionary* dic = arrayOfPercent[i];
  238. ZLCollectionViewLayoutAttributes *item = dic[@"item"];
  239. if ((item.frame.origin.y + item.frame.size.height) > maxYOfPercent) {
  240. maxYOfPercent = (item.frame.origin.y + item.frame.size.height);
  241. }
  242. }
  243. [arrayOfPercent removeAllObjects];
  244. } else {
  245. //先添加进总的数组
  246. attributes.indexPath = indexPath;
  247. attributes.frame = CGRectMake(0, maxYOfPercent, itemSize.width, itemSize.height);
  248. //再添加进计算比例的数组
  249. [arrayOfPercent addObject:[NSMutableDictionary dictionaryWithDictionary:@{@"item":attributes,@"percent":[NSNumber numberWithFloat:percent],@"indexPath":indexPath}]];
  250. //如果该行item总比例还是小于1,但是item已经是最后一个
  251. if (i==itemCount-1) {
  252. CGFloat realWidth = totalWidth - edgeInsets.left - edgeInsets.right - (arrayOfPercent.count-1)*minimumInteritemSpacing;
  253. for (NSInteger i=0; i<arrayOfPercent.count; i++) {
  254. NSDictionary* dic = arrayOfPercent[i];
  255. ZLCollectionViewLayoutAttributes *newAttributes = dic[@"item"];
  256. CGFloat itemX = 0.0f;
  257. if (i==0) {
  258. itemX = edgeInsets.left;
  259. } else {
  260. ZLCollectionViewLayoutAttributes *preAttr = arrayOfPercent[i-1][@"item"];
  261. itemX = preAttr.frame.origin.x + preAttr.frame.size.width + minimumInteritemSpacing;
  262. }
  263. newAttributes.frame = CGRectMake(itemX, maxYOfPercent+minimumLineSpacing, realWidth*[dic[@"percent"] floatValue], newAttributes.frame.size.height);
  264. newAttributes.indexPath = dic[@"indexPath"];
  265. [_attributesArray addObject:newAttributes];
  266. }
  267. for (NSInteger i=0; i<arrayOfPercent.count; i++) {
  268. NSDictionary* dic = arrayOfPercent[i];
  269. ZLCollectionViewLayoutAttributes *item = dic[@"item"];
  270. if ((item.frame.origin.y + item.frame.size.height) > maxYOfPercent) {
  271. maxYOfPercent = (item.frame.origin.y + item.frame.size.height);
  272. }
  273. }
  274. [arrayOfPercent removeAllObjects];
  275. }
  276. }
  277. } else {
  278. //先添加进总的数组
  279. attributes.indexPath = indexPath;
  280. NSDictionary* lastDicForPercent = arrayOfPercent[arrayOfPercent.count-1];
  281. ZLCollectionViewLayoutAttributes *lastAttributesForPercent = lastDicForPercent[@"item"];
  282. attributes.frame = CGRectMake(lastAttributesForPercent.frame.origin.x+lastAttributesForPercent.frame.size.width+minimumInteritemSpacing, lastAttributesForPercent.frame.origin.y, itemSize.width, itemSize.height);
  283. //再添加进计算比例的数组
  284. [arrayOfPercent addObject:[NSMutableDictionary dictionaryWithDictionary:@{@"item":attributes,@"percent":[NSNumber numberWithFloat:percent],@"indexPath":indexPath}]];
  285. //如果已经是最后一个
  286. if (i==itemCount-1) {
  287. CGFloat realWidth = totalWidth - edgeInsets.left - edgeInsets.right - (arrayOfPercent.count-1)*minimumInteritemSpacing;
  288. for (NSInteger i=0; i<arrayOfPercent.count; i++) {
  289. NSDictionary* dic = arrayOfPercent[i];
  290. ZLCollectionViewLayoutAttributes *newAttributes = dic[@"item"];
  291. CGFloat itemX = 0.0f;
  292. if (i==0) {
  293. itemX = edgeInsets.left;
  294. } else {
  295. ZLCollectionViewLayoutAttributes *preAttr = arrayOfPercent[i-1][@"item"];
  296. itemX = preAttr.frame.origin.x + preAttr.frame.size.width + minimumInteritemSpacing;
  297. }
  298. newAttributes.frame = CGRectMake(itemX, maxYOfPercent+minimumLineSpacing, realWidth*[dic[@"percent"] floatValue], newAttributes.frame.size.height);
  299. newAttributes.indexPath = dic[@"indexPath"];
  300. //if (![_attributesArray containsObject:newAttributes]) {
  301. [_attributesArray addObject:newAttributes];
  302. //}
  303. }
  304. for (NSInteger i=0; i<arrayOfPercent.count; i++) {
  305. NSDictionary* dic = arrayOfPercent[i];
  306. ZLCollectionViewLayoutAttributes *item = dic[@"item"];
  307. if ((item.frame.origin.y + item.frame.size.height) > maxYOfPercent) {
  308. maxYOfPercent = (item.frame.origin.y + item.frame.size.height);
  309. }
  310. }
  311. [arrayOfPercent removeAllObjects];
  312. }
  313. }
  314. } else {
  315. //先添加进总的数组
  316. attributes.indexPath = indexPath;
  317. attributes.frame = CGRectMake(edgeInsets.left, maxYOfPercent+minimumLineSpacing, itemSize.width, itemSize.height);
  318. //再添加进计算比例的数组
  319. [arrayOfPercent addObject:[NSMutableDictionary dictionaryWithDictionary:@{@"item":attributes,@"percent":[NSNumber numberWithFloat:percent],@"indexPath":indexPath}]];
  320. //如果已经是最后一个
  321. if (i==itemCount-1) {
  322. CGFloat realWidth = totalWidth - edgeInsets.left - edgeInsets.right - (arrayOfPercent.count-1)*minimumInteritemSpacing;
  323. for (NSInteger i=0; i<arrayOfPercent.count; i++) {
  324. NSDictionary* dic = arrayOfPercent[i];
  325. ZLCollectionViewLayoutAttributes *newAttributes = dic[@"item"];
  326. CGFloat itemX = 0.0f;
  327. if (i==0) {
  328. itemX = edgeInsets.left;
  329. } else {
  330. ZLCollectionViewLayoutAttributes *preAttr = arrayOfPercent[i-1][@"item"];
  331. itemX = preAttr.frame.origin.x + preAttr.frame.size.width + minimumInteritemSpacing;
  332. }
  333. newAttributes.frame = CGRectMake(itemX, maxYOfPercent+minimumLineSpacing, realWidth*[dic[@"percent"] floatValue], newAttributes.frame.size.height);
  334. newAttributes.indexPath = dic[@"indexPath"];
  335. [_attributesArray addObject:newAttributes];
  336. }
  337. for (NSInteger i=0; i<arrayOfPercent.count; i++) {
  338. NSDictionary* dic = arrayOfPercent[i];
  339. ZLCollectionViewLayoutAttributes *item = dic[@"item"];
  340. if ((item.frame.origin.y + item.frame.size.height) > maxYOfPercent) {
  341. maxYOfPercent = (item.frame.origin.y + item.frame.size.height);
  342. }
  343. }
  344. [arrayOfPercent removeAllObjects];
  345. }
  346. }
  347. }
  348. break;
  349. #pragma mark 填充布局处理
  350. case FillLayout: {
  351. if (arrayOfFill.count == 0) {
  352. attributes.frame = CGRectMake(edgeInsets.left, maxYOfFill, self.isFloor?floor(itemSize.width):itemSize.width, self.isFloor?floor(itemSize.height):itemSize.height);
  353. [arrayOfFill addObject:attributes];
  354. } else {
  355. NSMutableArray *arrayXOfFill = [NSMutableArray new];
  356. [arrayXOfFill addObject:@(edgeInsets.left)];
  357. NSMutableArray *arrayYOfFill = [NSMutableArray new];
  358. [arrayYOfFill addObject:self.isFloor?@(floor(maxYOfFill)):@(maxYOfFill)];
  359. for (ZLCollectionViewLayoutAttributes* attr in arrayOfFill) {
  360. if (![arrayXOfFill containsObject:@(attr.frame.origin.x)]) {
  361. [arrayXOfFill addObject:@(attr.frame.origin.x)];
  362. }
  363. if (![arrayXOfFill containsObject:@(attr.frame.origin.x+attr.frame.size.width)]) {
  364. [arrayXOfFill addObject:@(attr.frame.origin.x+attr.frame.size.width)];
  365. }
  366. if (![arrayYOfFill containsObject:@(attr.frame.origin.y)]) {
  367. [arrayYOfFill addObject:@(attr.frame.origin.y)];
  368. }
  369. if (![arrayYOfFill containsObject:@(attr.frame.origin.y+attr.frame.size.height)]) {
  370. [arrayYOfFill addObject:@(attr.frame.origin.y+attr.frame.size.height)];
  371. }
  372. }
  373. [arrayXOfFill sortUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
  374. return [obj1 floatValue] > [obj2 floatValue];
  375. }];
  376. [arrayYOfFill sortUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
  377. return [obj1 floatValue] > [obj2 floatValue];
  378. }];
  379. BOOL qualified = YES;
  380. for (NSNumber* yFill in arrayYOfFill) {
  381. for (NSNumber* xFill in arrayXOfFill) {
  382. qualified = YES;
  383. attributes.frame = CGRectMake([xFill floatValue]==edgeInsets.left?[xFill floatValue]:[xFill floatValue]+minimumInteritemSpacing, [yFill floatValue]==maxYOfFill?(self.isFloor?floor([yFill floatValue]):[yFill floatValue]):[yFill floatValue]+minimumLineSpacing, self.isFloor?floor(itemSize.width):itemSize.width, self.isFloor?floor(itemSize.height):itemSize.height);
  384. if (attributes.frame.origin.x+attributes.frame.size.width > totalWidth-edgeInsets.right) {
  385. qualified = NO;
  386. break;
  387. }
  388. for (ZLCollectionViewLayoutAttributes* attr in arrayOfFill) {
  389. if (CGRectIntersectsRect(attributes.frame, attr.frame)) {
  390. qualified = NO;
  391. break;
  392. }
  393. }
  394. if (qualified == NO) {
  395. continue;
  396. } else {
  397. CGPoint leftPt = CGPointMake(attributes.frame.origin.x - minimumInteritemSpacing, attributes.frame.origin.y);
  398. CGRect leftRect = CGRectZero;
  399. for (ZLCollectionViewLayoutAttributes* attr in arrayOfFill) {
  400. if (CGRectContainsPoint(attr.frame, leftPt)) {
  401. leftRect = attr.frame;
  402. break;
  403. }
  404. }
  405. if (CGRectEqualToRect(leftRect, CGRectZero)) {
  406. break;
  407. } else {
  408. if (attributes.frame.origin.x - (leftRect.origin.x + leftRect.size.width) == minimumInteritemSpacing) {
  409. break;
  410. } else {
  411. CGRect rc = attributes.frame;
  412. rc.origin.x = leftRect.origin.x + leftRect.size.width + minimumInteritemSpacing;
  413. attributes.frame = rc;
  414. for (ZLCollectionViewLayoutAttributes* attr in arrayOfFill) {
  415. if (CGRectIntersectsRect(attributes.frame, attr.frame)) {
  416. qualified = NO;
  417. break;
  418. }
  419. }
  420. }
  421. }
  422. }
  423. }
  424. if (qualified == YES) {
  425. break;
  426. }
  427. }
  428. if (qualified == YES) {
  429. //NSLog(@"合格的矩形区域=%@",NSStringFromCGRect(attributes.frame));
  430. }
  431. [arrayOfFill addObject:attributes];
  432. }
  433. }
  434. break;
  435. #pragma mark 绝对定位布局处理
  436. case AbsoluteLayout: {
  437. CGRect itemFrame = CGRectZero;
  438. if (_delegate && [_delegate respondsToSelector:@selector(collectionView:layout:rectOfItem:)]) {
  439. itemFrame = [_delegate collectionView:self.collectionView layout:self rectOfItem:indexPath];
  440. }
  441. CGFloat absolute_x = edgeInsets.left+itemFrame.origin.x;
  442. CGFloat absolute_y = y+itemFrame.origin.y;
  443. CGFloat absolute_w = itemFrame.size.width;
  444. if ((absolute_x+absolute_w>self.collectionView.frame.size.width-edgeInsets.right)&&(absolute_x<self.collectionView.frame.size.width-edgeInsets.right)) {
  445. absolute_w -= (absolute_x+absolute_w-(self.collectionView.frame.size.width-edgeInsets.right));
  446. }
  447. CGFloat absolute_h = itemFrame.size.height;
  448. attributes.frame = CGRectMake(absolute_x, absolute_y, absolute_w, absolute_h);
  449. [arrayOfAbsolute addObject:attributes];
  450. }
  451. break;
  452. default: {
  453. //NSLog(@"%@",NSStringFromCGRect(attributes.frame));
  454. }
  455. break;
  456. }
  457. if (_delegate && [_delegate respondsToSelector:@selector(collectionView:layout:transformOfItem:)]) {
  458. attributes.transform3D = [_delegate collectionView:self.collectionView layout:self transformOfItem:indexPath];
  459. }
  460. if (_delegate && [_delegate respondsToSelector:@selector(collectionView:layout:zIndexOfItem:)]) {
  461. attributes.zIndex = [_delegate collectionView:self.collectionView layout:self zIndexOfItem:indexPath];
  462. }
  463. if (_delegate && [_delegate respondsToSelector:@selector(collectionView:layout:alphaOfItem:)]) {
  464. attributes.alpha = [_delegate collectionView:self.collectionView layout:self alphaOfItem:indexPath];
  465. }
  466. attributes.indexPath = indexPath;
  467. if (self.layoutType != PercentLayout) {
  468. //if (![_attributesArray containsObject:attributes]) {
  469. [_attributesArray addObject:attributes];
  470. //}
  471. }
  472. if (self.layoutType == ClosedLayout) {
  473. CGFloat max = 0;
  474. for (int i = 0; i < self.columnCount; i++) {
  475. if (columnHeight[i] > max) {
  476. max = columnHeight[i];
  477. }
  478. }
  479. lastY = max;
  480. } else if (self.layoutType == PercentLayout) {
  481. lastY = maxYOfPercent;
  482. } else if (self.layoutType == FillLayout) {
  483. if (i==itemCount-1) {
  484. for (ZLCollectionViewLayoutAttributes* attr in arrayOfFill) {
  485. if (maxYOfFill < attr.frame.origin.y+attr.frame.size.height) {
  486. maxYOfFill = attr.frame.origin.y+attr.frame.size.height;
  487. }
  488. }
  489. }
  490. lastY = maxYOfFill;
  491. } else if (self.layoutType == AbsoluteLayout) {
  492. if (i==itemCount-1) {
  493. for (ZLCollectionViewLayoutAttributes* attr in arrayOfAbsolute) {
  494. if (lastY < attr.frame.origin.y+attr.frame.size.height) {
  495. lastY = attr.frame.origin.y+attr.frame.size.height;
  496. }
  497. }
  498. }
  499. } else {
  500. lastY = attributes.frame.origin.y + attributes.frame.size.height;
  501. }
  502. }
  503. }
  504. lastY += edgeInsets.bottom;
  505. if (_delegate && [_delegate respondsToSelector:@selector(collectionView:layout:registerBackView:)]) {
  506. NSString* className = [_delegate collectionView:self.collectionView layout:self registerBackView:index];
  507. if (className != nil && className.length > 0) {
  508. ZLCollectionViewLayoutAttributes *attr = [ZLCollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:className withIndexPath:[NSIndexPath indexPathForRow:0 inSection:index]];
  509. attr.frame = CGRectMake(0, [self isAttachToTop:index]?itemStartY-headerH:itemStartY, self.collectionView.frame.size.width, lastY-itemStartY+([self isAttachToTop:index]?headerH:0));
  510. attr.zIndex = -1000;
  511. [_attributesArray addObject:attr];
  512. if (_delegate && [_delegate respondsToSelector:@selector(collectionView:layout:loadView:)]) {
  513. [_delegate collectionView:self.collectionView layout:self loadView:index];
  514. }
  515. } else {
  516. ZLCollectionViewLayoutAttributes *attr = [ZLCollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:@"ZLCollectionReusableView" withIndexPath:[NSIndexPath indexPathForRow:0 inSection:index]];
  517. attr.frame = CGRectMake(0, [self isAttachToTop:index]?itemStartY-headerH:itemStartY, self.collectionView.frame.size.width, lastY-itemStartY+([self isAttachToTop:index]?headerH:0));
  518. attr.color = self.collectionView.backgroundColor;
  519. if (_delegate && [_delegate respondsToSelector:@selector(collectionView:layout:backColorForSection:)]) {
  520. attr.color = [_delegate collectionView:self.collectionView layout:self backColorForSection:index];
  521. }
  522. attr.zIndex = -1000;
  523. [_attributesArray addObject:attr];
  524. }
  525. } else {
  526. ZLCollectionViewLayoutAttributes *attr = [ZLCollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:@"ZLCollectionReusableView" withIndexPath:[NSIndexPath indexPathForRow:0 inSection:index]];
  527. attr.frame = CGRectMake(0, [self isAttachToTop:index]?itemStartY-headerH:itemStartY, self.collectionView.frame.size.width, lastY-itemStartY+([self isAttachToTop:index]?headerH:0));
  528. attr.color = self.collectionView.backgroundColor;
  529. if (_delegate && [_delegate respondsToSelector:@selector(collectionView:layout:backColorForSection:)]) {
  530. attr.color = [_delegate collectionView:self.collectionView layout:self backColorForSection:index];
  531. }
  532. attr.zIndex = -1000;
  533. [_attributesArray addObject:attr];
  534. }
  535. // 添加页脚属性
  536. if (footerH > 0) {
  537. NSIndexPath *footerIndexPath = [NSIndexPath indexPathForItem:0 inSection:index];
  538. ZLCollectionViewLayoutAttributes *footerAttr = [ZLCollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionFooter withIndexPath:footerIndexPath];
  539. footerAttr.frame = CGRectMake(0, lastY, self.collectionView.frame.size.width, footerH);
  540. [_attributesArray addObject:footerAttr];
  541. lastY += footerH;
  542. }
  543. _collectionHeightsArray[index] = [NSNumber numberWithFloat:lastY];
  544. }
  545. }
  546. #pragma mark - 所有cell和view的布局属性
  547. //sectionheader sectionfooter decorationview collectionviewcell的属性都会走这个方法
  548. - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
  549. {
  550. if (!_attributesArray) {
  551. return [super layoutAttributesForElementsInRect:rect];
  552. } else {
  553. if (self.header_suspension) {
  554. for (UICollectionViewLayoutAttributes *attriture in _attributesArray) {
  555. if (![attriture.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) continue;
  556. NSInteger section = attriture.indexPath.section;
  557. CGRect frame = attriture.frame;
  558. if (section == 0) {
  559. if (self.collectionView.contentOffset.y > 0 && self.collectionView.contentOffset.y < [self.collectionHeightsArray[0] floatValue]) {
  560. frame.origin.y = self.collectionView.contentOffset.y;
  561. }
  562. } else {
  563. if (self.collectionView.contentOffset.y > [self.collectionHeightsArray[section-1] floatValue] && self.collectionView.contentOffset.y < [self.collectionHeightsArray[section] floatValue]) {
  564. frame.origin.y = self.collectionView.contentOffset.y;
  565. }
  566. }
  567. attriture.zIndex = 1000+section;
  568. attriture.frame = frame;
  569. }
  570. }
  571. return _attributesArray;
  572. }
  573. }
  574. #pragma mark - CollectionView的滚动范围
  575. - (CGSize)collectionViewContentSize
  576. {
  577. CGFloat footerH = 0.0f;
  578. if (_delegate && [_delegate respondsToSelector:@selector(collectionView:layout:referenceSizeForFooterInSection:)]) {
  579. footerH = [_delegate collectionView:self.collectionView layout:self referenceSizeForFooterInSection:_collectionHeightsArray.count-1].height;
  580. } else {
  581. footerH = self.footerReferenceSize.height;
  582. }
  583. UIEdgeInsets edgeInsets = UIEdgeInsetsZero;
  584. if (_delegate && [_delegate respondsToSelector:@selector(collectionView:layout:insetForSectionAtIndex:)]) {
  585. edgeInsets = [_delegate collectionView:self.collectionView layout:self insetForSectionAtIndex:_collectionHeightsArray.count-1];
  586. } else {
  587. edgeInsets = self.sectionInset;
  588. }
  589. if (_collectionHeightsArray.count > 0) {
  590. return CGSizeMake(self.collectionView.frame.size.width, [_collectionHeightsArray[_collectionHeightsArray.count-1] floatValue]);// + edgeInsets.bottom + footerH);
  591. } else {
  592. return CGSizeMake(self.collectionView.frame.size.width, self.collectionView.frame.size.height);
  593. }
  594. }
  595. /**
  596. 每个区的初始Y坐标
  597. @param section 区索引
  598. @return Y坐标
  599. */
  600. - (CGFloat)maxHeightWithSection:(NSInteger)section {
  601. if (section>0) {
  602. return [_collectionHeightsArray[section-1] floatValue];
  603. } else {
  604. return 0;
  605. }
  606. }
  607. - (BOOL)isAttachToTop:(NSInteger)section {
  608. if (_delegate && [_delegate respondsToSelector:@selector(collectionView:layout:attachToTop:)]) {
  609. return [_delegate collectionView:self.collectionView layout:self attachToTop:section];
  610. }
  611. return NO;
  612. }
  613. #pragma mark 以下是拖动排序的代码
  614. - (void)setCanDrag:(BOOL)canDrag {
  615. _canDrag = canDrag;
  616. if (canDrag) {
  617. if (self.longPress == nil && self.panGesture == nil) {
  618. [self setUpGestureRecognizers];
  619. }
  620. } else {
  621. [self.collectionView removeGestureRecognizer:self.longPress];
  622. self.longPress.delegate = nil;
  623. self.longPress = nil;
  624. [self.collectionView removeGestureRecognizer:self.panGesture];
  625. self.panGesture.delegate = nil;
  626. self.panGesture = nil;
  627. }
  628. }
  629. - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
  630. if ([keyPath isEqualToString:@"collectionView"]) {
  631. if (self.canDrag) {
  632. [self setUpGestureRecognizers];
  633. }
  634. }else{
  635. [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
  636. }
  637. }
  638. - (void)setUpGestureRecognizers{
  639. if (self.collectionView == nil) {
  640. return;
  641. }
  642. self.longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(handleLongPress:)];
  643. self.panGesture = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(handlePanGesture:)];
  644. self.longPress.delegate = self;
  645. self.panGesture.delegate = self;
  646. self.panGesture.maximumNumberOfTouches = 1;
  647. NSArray *gestures = [self.collectionView gestureRecognizers];
  648. __weak typeof(ZLCollectionViewFlowLayout*) weakSelf = self;
  649. [gestures enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
  650. if ([obj isKindOfClass:[UILongPressGestureRecognizer class]]) {
  651. [(UILongPressGestureRecognizer *)obj requireGestureRecognizerToFail:weakSelf.longPress];
  652. }
  653. }];
  654. [self.collectionView addGestureRecognizer:self.longPress];
  655. [self.collectionView addGestureRecognizer:self.panGesture];
  656. }
  657. #pragma mark - gesture
  658. - (void)handleLongPress:(UILongPressGestureRecognizer *)longPress {
  659. CGPoint location = [longPress locationInView:self.collectionView];
  660. NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:location];
  661. if (_cellFakeView != nil) {
  662. indexPath = self.cellFakeView.indexPath;
  663. }
  664. if (indexPath == nil) {
  665. return;
  666. }
  667. switch (longPress.state) {
  668. case UIGestureRecognizerStateBegan:{
  669. // will begin drag item
  670. self.collectionView.scrollsToTop = NO;
  671. UICollectionViewCell *currentCell = [self.collectionView cellForItemAtIndexPath:indexPath];
  672. self.cellFakeView = [[ZLCellFakeView alloc]initWithCell:currentCell];
  673. self.cellFakeView.indexPath = indexPath;
  674. self.cellFakeView.originalCenter = currentCell.center;
  675. self.cellFakeView.cellFrame = [self layoutAttributesForItemAtIndexPath:indexPath].frame;
  676. [self.collectionView addSubview:self.cellFakeView];
  677. self.fakeCellCenter = self.cellFakeView.center;
  678. [self invalidateLayout];
  679. [self.cellFakeView pushFowardView];
  680. }
  681. break;
  682. case UIGestureRecognizerStateCancelled:
  683. case UIGestureRecognizerStateEnded:
  684. [self cancelDrag:indexPath];
  685. default:
  686. break;
  687. }
  688. }
  689. // pan gesture
  690. - (void)handlePanGesture:(UIPanGestureRecognizer *)pan {
  691. _panTranslation = [pan translationInView:self.collectionView];
  692. if (_cellFakeView != nil) {
  693. switch (pan.state) {
  694. case UIGestureRecognizerStateChanged:{
  695. CGPoint center = _cellFakeView.center;
  696. center.x = self.fakeCellCenter.x + self.panTranslation.x;
  697. center.y = self.fakeCellCenter.y + self.panTranslation.y;
  698. self.cellFakeView.center = center;
  699. [self beginScrollIfNeeded];
  700. [self moveItemIfNeeded];
  701. }
  702. break;
  703. case UIGestureRecognizerStateCancelled:
  704. case UIGestureRecognizerStateEnded:
  705. [self invalidateDisplayLink];
  706. default:
  707. break;
  708. }
  709. }
  710. }
  711. // gesture recognize delegate
  712. - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
  713. // allow move item
  714. CGPoint location = [gestureRecognizer locationInView:self.collectionView];
  715. NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:location];
  716. if (!indexPath) {
  717. return NO;
  718. }
  719. if ([gestureRecognizer isEqual:self.longPress]){
  720. return (self.collectionView.panGestureRecognizer.state == UIGestureRecognizerStatePossible || self.collectionView.panGestureRecognizer.state == UIGestureRecognizerStateFailed);
  721. } else if ([gestureRecognizer isEqual:self.panGesture]){
  722. return (self.longPress.state != UIGestureRecognizerStatePossible && self.longPress.state != UIGestureRecognizerStateFailed);
  723. }
  724. return YES;
  725. }
  726. - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
  727. if ([self.panGesture isEqual:gestureRecognizer]) {
  728. return [self.longPress isEqual:otherGestureRecognizer];
  729. } else if ([self.collectionView.panGestureRecognizer isEqual:gestureRecognizer]) {
  730. return (self.longPress.state != UIGestureRecognizerStatePossible && self.longPress.state != UIGestureRecognizerStateFailed);
  731. }
  732. return YES;
  733. }
  734. - (void)cancelDrag:(NSIndexPath *)toIndexPath {
  735. if (self.cellFakeView == nil) {
  736. return;
  737. }
  738. self.collectionView.scrollsToTop = YES;
  739. self.fakeCellCenter = CGPointZero;
  740. [self invalidateDisplayLink];
  741. __weak typeof(ZLCollectionViewFlowLayout*) weakSelf = self;
  742. [self.cellFakeView pushBackView:^{
  743. [weakSelf.cellFakeView removeFromSuperview];
  744. weakSelf.cellFakeView = nil;
  745. [weakSelf invalidateLayout];
  746. }];
  747. }
  748. - (void)beginScrollIfNeeded{
  749. if (self.cellFakeView == nil) {
  750. return;
  751. }
  752. CGFloat offset = self.collectionView.contentOffset.y;
  753. CGFloat trigerInsetTop = self.collectionView.contentInset.top;
  754. CGFloat trigerInsetEnd = self.collectionView.contentInset.bottom;
  755. CGFloat paddingTop = 0;
  756. CGFloat paddingEnd = 0;
  757. CGFloat length = self.collectionView.frame.size.height;
  758. CGFloat fakeCellTopEdge = CGRectGetMinY(self.cellFakeView.frame);
  759. CGFloat fakeCellEndEdge = CGRectGetMaxY(self.cellFakeView.frame);
  760. if(fakeCellTopEdge <= offset + paddingTop + trigerInsetTop){
  761. self.continuousScrollDirection = LewScrollDirctionToTop;
  762. [self setUpDisplayLink];
  763. }else if(fakeCellEndEdge >= offset + length - paddingEnd - trigerInsetEnd) {
  764. self.continuousScrollDirection = LewScrollDirctionToEnd;
  765. [self setUpDisplayLink];
  766. }else {
  767. [self invalidateDisplayLink];
  768. }
  769. }
  770. // move item
  771. - (void)moveItemIfNeeded {
  772. NSIndexPath *atIndexPath = nil;
  773. NSIndexPath *toIndexPath = nil;
  774. if (self.cellFakeView) {
  775. atIndexPath = _cellFakeView.indexPath;
  776. toIndexPath = [self.collectionView indexPathForItemAtPoint:_cellFakeView.center];
  777. }
  778. if (atIndexPath.section != toIndexPath.section) {
  779. return;
  780. }
  781. if (atIndexPath == nil || toIndexPath == nil) {
  782. return;
  783. }
  784. if ([atIndexPath isEqual:toIndexPath]) {
  785. return;
  786. }
  787. UICollectionViewLayoutAttributes *attribute = nil;//[self layoutAttributesForItemAtIndexPath:toIndexPath];
  788. for (ZLCollectionViewLayoutAttributes* attr in self.attributesArray) {
  789. if (attr.indexPath.section == toIndexPath.section && attr.indexPath.item == toIndexPath.item &&
  790. attr.representedElementKind != UICollectionElementKindSectionHeader &&
  791. attr.representedElementKind != UICollectionElementKindSectionFooter) {
  792. attribute = attr;
  793. break;
  794. }
  795. }
  796. if (attribute != nil) {
  797. __weak typeof(ZLCollectionViewFlowLayout*) weakSelf = self;
  798. [self.collectionView performBatchUpdates:^{
  799. weakSelf.cellFakeView.indexPath = toIndexPath;
  800. weakSelf.cellFakeView.cellFrame = attribute.frame;
  801. [weakSelf.cellFakeView changeBoundsIfNeeded:attribute.bounds];
  802. [weakSelf.collectionView moveItemAtIndexPath:atIndexPath toIndexPath:toIndexPath];
  803. if ([weakSelf.delegate respondsToSelector:@selector(collectionView:layout:didMoveCell:toIndexPath:)]) {
  804. [weakSelf.delegate collectionView:weakSelf.collectionView layout:weakSelf didMoveCell:atIndexPath toIndexPath:toIndexPath];
  805. }
  806. } completion:nil];
  807. }
  808. }
  809. - (void)setUpDisplayLink{
  810. if (_displayLink) {
  811. return;
  812. }
  813. _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(continuousScroll)];
  814. [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
  815. }
  816. - (void)invalidateDisplayLink{
  817. _continuousScrollDirection = LewScrollDirctionStay;
  818. [_displayLink invalidate];
  819. _displayLink = nil;
  820. }
  821. - (void)continuousScroll{
  822. if (_cellFakeView == nil) {
  823. return;
  824. }
  825. CGFloat percentage = [self calcTrigerPercentage];
  826. CGFloat scrollRate = [self scrollValueWithSpeed:10 andPercentage:percentage];
  827. CGFloat offset = 0;
  828. CGFloat insetTop = 0;
  829. CGFloat insetEnd = 0;
  830. CGFloat length = self.collectionView.frame.size.height;
  831. CGFloat contentLength = self.collectionView.contentSize.height;
  832. if (contentLength + insetTop + insetEnd <= length) {
  833. return;
  834. }
  835. if (offset + scrollRate <= -insetTop) {
  836. scrollRate = -insetTop - offset;
  837. } else if (offset + scrollRate >= contentLength + insetEnd - length) {
  838. scrollRate = contentLength + insetEnd - length - offset;
  839. }
  840. __weak typeof(ZLCollectionViewFlowLayout*) weakSelf = self;
  841. [self.collectionView performBatchUpdates:^{
  842. if (weakSelf.scrollDirection == UICollectionViewScrollDirectionVertical) {
  843. CGPoint point = weakSelf.fakeCellCenter;
  844. point.y += scrollRate;
  845. weakSelf.fakeCellCenter = point;
  846. CGPoint center = weakSelf.cellFakeView.center;
  847. center.y = weakSelf.fakeCellCenter.y + weakSelf.panTranslation.y;
  848. weakSelf.cellFakeView.center = center;
  849. CGPoint contentOffset = weakSelf.collectionView.contentOffset;
  850. contentOffset.y += scrollRate;
  851. weakSelf.collectionView.contentOffset = contentOffset;
  852. } else {
  853. CGPoint point = weakSelf.fakeCellCenter;
  854. point.x += scrollRate;
  855. weakSelf.fakeCellCenter = point;
  856. //_fakeCellCenter.x += scrollRate;
  857. CGPoint center = weakSelf.cellFakeView.center;
  858. center.x = weakSelf.fakeCellCenter.x + weakSelf.panTranslation.x;
  859. weakSelf.cellFakeView.center = center;
  860. CGPoint contentOffset = weakSelf.collectionView.contentOffset;
  861. contentOffset.x += scrollRate;
  862. weakSelf.collectionView.contentOffset = contentOffset;
  863. }
  864. } completion:nil];
  865. [self moveItemIfNeeded];
  866. }
  867. - (CGFloat)calcTrigerPercentage{
  868. if (_cellFakeView == nil) {
  869. return 0;
  870. }
  871. CGFloat offset = 0;
  872. CGFloat offsetEnd = 0 + self.collectionView.frame.size.height;
  873. CGFloat insetTop = 0;
  874. CGFloat trigerInsetTop = 0;
  875. CGFloat trigerInsetEnd = 0;
  876. CGFloat paddingTop = 0;
  877. CGFloat paddingEnd = 0;
  878. CGFloat percentage = 0.0;
  879. if (self.continuousScrollDirection == LewScrollDirctionToTop) {
  880. if (self.cellFakeView) {
  881. percentage = 1.0 - ((self.cellFakeView.frame.origin.y - (offset + paddingTop)) / trigerInsetTop);
  882. }
  883. } else if (self.continuousScrollDirection == LewScrollDirctionToEnd){
  884. if (self.cellFakeView) {
  885. percentage = 1.0 - (((insetTop + offsetEnd - paddingEnd) - (self.cellFakeView.frame.origin.y + self.cellFakeView.frame.size.height + insetTop)) / trigerInsetEnd);
  886. }
  887. }
  888. percentage = fmin(1.0f, percentage);
  889. percentage = fmax(0.0f, percentage);
  890. return percentage;
  891. }
  892. #pragma mark - getter
  893. - (CGFloat)scrollValueWithSpeed:(CGFloat)speed andPercentage:(CGFloat)percentage{
  894. CGFloat value = 0.0f;
  895. switch (_continuousScrollDirection) {
  896. case LewScrollDirctionStay: {
  897. return 0.0f;
  898. break;
  899. }
  900. case LewScrollDirctionToTop: {
  901. value = -speed;
  902. break;
  903. }
  904. case LewScrollDirctionToEnd: {
  905. value = speed;
  906. break;
  907. }
  908. default: {
  909. return 0.0f;
  910. }
  911. }
  912. CGFloat proofedPercentage = fmax(fmin(1.0f, percentage), 0.0f);
  913. return value * proofedPercentage;
  914. }
  915. @end