WMZBannerFlowLayout.m 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. //
  2. // WMZBannerFlowLayout.m
  3. // WMZBanner
  4. //
  5. // Created by wmz on 2019/9/6.
  6. // Copyright © 2019 wmz. All rights reserved.
  7. //
  8. #import "WMZBannerFlowLayout.h"
  9. @interface WMZBannerFlowLayout(){
  10. CGSize factItemSize;
  11. }
  12. @end
  13. @implementation WMZBannerFlowLayout
  14. - (instancetype)initConfigureWithModel:(WMZBannerParam *)param{
  15. if (self = [super init]) {
  16. self.param = param;
  17. }
  18. return self;
  19. }
  20. - (void)prepareLayout
  21. {
  22. [super prepareLayout];
  23. self.itemSize = self.param.wItemSize;
  24. self.minimumInteritemSpacing = (self.param.wFrame.size.height-self.param.wItemSize.height)/2;
  25. self.minimumLineSpacing = self.param.wLineSpacing;
  26. self.sectionInset = self.param.wSectionInset;
  27. if ([self.collectionView isPagingEnabled]) {
  28. self.scrollDirection = self.param.wVertical? UICollectionViewScrollDirectionVertical
  29. :UICollectionViewScrollDirectionHorizontal;
  30. }else{
  31. self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
  32. }
  33. }
  34. - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
  35. return [self cardScaleTypeInRect:rect];
  36. }
  37. //卡片缩放
  38. - (NSArray<UICollectionViewLayoutAttributes *> *)cardScaleTypeInRect:(CGRect)rect{
  39. [self setUpIndex];
  40. NSArray *array = [self getCopyOfAttributes:[super layoutAttributesForElementsInRect:rect]];
  41. if (!self.param.wScale||self.param.wMarquee) {
  42. return array;
  43. }
  44. CGRect visibleRect = CGRectZero;
  45. visibleRect.origin = self.collectionView.contentOffset;
  46. visibleRect.size = self.collectionView.bounds.size;
  47. NSMutableArray *marr = [NSMutableArray new];
  48. NSInteger minIndex = 0;
  49. CGFloat minCenterX = [(UICollectionViewLayoutAttributes*)array.firstObject center].x;
  50. for (int i = 0; i<array.count; i++) {
  51. UICollectionViewLayoutAttributes *attributes = array[i];
  52. CGRect cellFrameInSuperview = [self.collectionView convertRect:attributes.frame toView:self.collectionView.superview];
  53. if (cellFrameInSuperview.origin.x>=0&&
  54. cellFrameInSuperview.origin.x<=self.collectionView.frame.size.width) {
  55. if (minCenterX>cellFrameInSuperview.origin.x) {
  56. minCenterX = cellFrameInSuperview.origin.x;
  57. minIndex = i;
  58. }
  59. }
  60. }
  61. for (int i = 0; i<array.count; i++) {
  62. UICollectionViewLayoutAttributes *attributes = array[i];
  63. CGFloat distance = CGRectGetMidX(visibleRect) - attributes.center.x;
  64. if (self.param.wContentOffsetX!=0.5) {
  65. distance = CGRectGetMidX(visibleRect) - (attributes.center.x + (0.5-self.param.wContentOffsetX)*visibleRect.size.width);
  66. }
  67. if (self.param.wSpecialStyle == SpecialStyleFirstScale) {
  68. distance = CGRectGetMinX(visibleRect) - attributes.center.x;
  69. }
  70. CGFloat normalizedDistance = fabs(distance / self.param.wActiveDistance);
  71. CGFloat zoom = 1 - self.param.wScaleFactor * normalizedDistance;
  72. if (self.param.wSpecialStyle == SpecialStyleFirstScale) {
  73. if (i == minIndex) {
  74. attributes.transform3D = CATransform3DMakeScale(1.0, zoom+0.6, 1.0);
  75. }else{
  76. attributes.transform3D = CATransform3DMakeScale(1.0, 1.0, 1.0);
  77. }
  78. }else{
  79. attributes.transform3D = CATransform3DMakeScale(1.0, zoom, 1.0);
  80. }
  81. if (self.param.wAlpha<1) {
  82. CGFloat collectionCenter = self.collectionView.frame.size.width / 2 ;
  83. CGFloat offset = self.collectionView.contentOffset.x ;
  84. CGFloat normalizedCenter = attributes.center.x - offset;
  85. CGFloat maxDistance = (self.itemSize.width) + self.minimumLineSpacing;
  86. CGFloat distance1 = MIN(fabs(collectionCenter - normalizedCenter), maxDistance);
  87. CGFloat ratio = (maxDistance - distance1) / maxDistance;
  88. CGFloat alpha = ratio * (1 - self.param.wAlpha) +self.param.wAlpha;
  89. attributes.alpha = alpha;
  90. }
  91. if (self.param.wZindex) {
  92. attributes.zIndex = zoom*100;
  93. }
  94. CGPoint center = CGPointMake(attributes.center.x, self.collectionView.center.y );
  95. if (self.param.wPosition == BannerCellPositionBottom) {
  96. center = CGPointMake(attributes.center.x, attributes.center.y + attributes.size.height*(1-zoom));
  97. attributes.center = center;
  98. }else if (self.param.wPosition == BannerCellPositionTop) {
  99. center = CGPointMake(attributes.center.x, attributes.center.y- attributes.size.height*(1-zoom));
  100. attributes.center = center;
  101. }else if (self.param.wPosition == BannerCellPositionCenter) {
  102. attributes.center = center;
  103. }
  104. [marr addObject:attributes];
  105. }
  106. return marr;
  107. }
  108. - (void)setUpIndex{
  109. if (!self.param.wCardOverLap) {
  110. self.param.myCurrentPath = self.param.wVertical?
  111. round((ABS(self.collectionView.contentOffset.y))/(self.param.wItemSize.height+self.param.wLineSpacing)):
  112. round ((ABS(self.collectionView.contentOffset.x))/(self.param.wItemSize.width+self.param.wLineSpacing));
  113. }
  114. }
  115. - (NSArray *)getCopyOfAttributes:(NSArray *)attributes
  116. {
  117. NSMutableArray *copyArr = [NSMutableArray new];
  118. for (UICollectionViewLayoutAttributes *attribute in attributes) {
  119. [copyArr addObject:[attribute copy]];
  120. }
  121. return copyArr;
  122. }
  123. - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
  124. if (self.param.wMarquee){
  125. return NO;
  126. }
  127. return ![self.collectionView isPagingEnabled];
  128. }
  129. /**
  130. * collectionView停止滚动时的偏移量
  131. */
  132. - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
  133. {
  134. if ([self.collectionView isPagingEnabled]||self.param.wMarquee) {
  135. return proposedContentOffset;
  136. }
  137. CGFloat offSetAdjustment = MAXFLOAT;
  138. CGFloat horizontalCenter = (CGFloat) (proposedContentOffset.x + self.collectionView.frame.size.width * self.param.wContentOffsetX);
  139. CGRect targetRect = CGRectMake(proposedContentOffset.x,
  140. 0.0,
  141. self.collectionView.bounds.size.width,
  142. self.collectionView.bounds.size.height);
  143. NSArray *attributes = [self layoutAttributesForElementsInRect:targetRect];
  144. NSPredicate *cellAttributesPredicate = [NSPredicate predicateWithBlock: ^BOOL(UICollectionViewLayoutAttributes * _Nonnull evaluatedObject,NSDictionary<NSString *,id> * _Nullable bindings){
  145. return (evaluatedObject.representedElementCategory == UICollectionElementCategoryCell);
  146. }];
  147. NSArray *cellAttributes = [attributes filteredArrayUsingPredicate: cellAttributesPredicate];
  148. UICollectionViewLayoutAttributes *currentAttributes;
  149. for (UICollectionViewLayoutAttributes *layoutAttributes in cellAttributes)
  150. {
  151. CGFloat itemHorizontalCenter = layoutAttributes.center.x;
  152. if (ABS(itemHorizontalCenter - horizontalCenter) < ABS(offSetAdjustment))
  153. {
  154. currentAttributes = layoutAttributes;
  155. offSetAdjustment = itemHorizontalCenter - horizontalCenter;
  156. }
  157. }
  158. CGFloat nextOffset = proposedContentOffset.x + offSetAdjustment;
  159. proposedContentOffset.x = nextOffset;
  160. CGFloat deltaX = proposedContentOffset.x - self.collectionView.contentOffset.x;
  161. CGFloat velX = velocity.x;
  162. if (fabs(deltaX) <= FLT_EPSILON || fabs(velX) <= FLT_EPSILON || (velX > 0.0 && deltaX > 0.0) || (velX < 0.0 && deltaX < 0.0))
  163. {
  164. }else if (velocity.x > 0.0){
  165. NSArray *revertedArray = [[attributes reverseObjectEnumerator] allObjects];
  166. BOOL found = YES;
  167. float proposedX = 0.0;
  168. for (UICollectionViewLayoutAttributes *layoutAttributes in revertedArray)
  169. {
  170. if(layoutAttributes.representedElementCategory == UICollectionElementCategoryCell)
  171. {
  172. CGFloat itemHorizontalCenter = layoutAttributes.center.x;
  173. if (itemHorizontalCenter > proposedContentOffset.x) {
  174. found = YES;
  175. proposedX = nextOffset + (currentAttributes.frame.size.width / 2) + (layoutAttributes.frame.size.width / 2);
  176. } else {
  177. break;
  178. }
  179. }
  180. }
  181. if (found) {
  182. proposedContentOffset.x = proposedX;
  183. proposedContentOffset.x += self.param.wLineSpacing;
  184. }
  185. }
  186. else if (velocity.x < 0.0)
  187. {
  188. for (UICollectionViewLayoutAttributes *layoutAttributes in cellAttributes)
  189. {
  190. CGFloat itemHorizontalCenter = layoutAttributes.center.x;
  191. if (itemHorizontalCenter > proposedContentOffset.x)
  192. {
  193. proposedContentOffset.x = nextOffset - ((currentAttributes.frame.size.width / 2) + (layoutAttributes.frame.size.width / 2));
  194. proposedContentOffset.x -= self.param.wLineSpacing;
  195. break;
  196. }
  197. }
  198. }
  199. proposedContentOffset.y = 0.0;
  200. return proposedContentOffset;
  201. }
  202. @end