WMZBannerFlowLayout.m 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  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. if (!self.param.wCardOverLap) {
  40. self.param.myCurrentPath =
  41. round((ABS(self.collectionView.contentOffset.x))/(self.param.wItemSize.width+self.param.wLineSpacing));
  42. }
  43. NSArray *array = [self getCopyOfAttributes:[super layoutAttributesForElementsInRect:rect]];
  44. if (!self.param.wScale||self.param.wMarquee) {
  45. return array;
  46. }
  47. CGRect visibleRect = CGRectZero;
  48. visibleRect.origin = self.collectionView.contentOffset;
  49. visibleRect.size = self.collectionView.bounds.size;
  50. for (int i = 0; i<array.count; i++) {
  51. UICollectionViewLayoutAttributes *attributes = array[i];
  52. CGFloat distance = CGRectGetMidX(visibleRect) - attributes.center.x;
  53. CGFloat normalizedDistance = fabs(distance / self.param.wActiveDistance);
  54. CGFloat zoom = 1 - self.param.wScaleFactor * normalizedDistance;
  55. attributes.transform3D = CATransform3DMakeScale(1.0, zoom, 1.0);
  56. attributes.frame = CGRectMake(attributes.frame.origin.x, attributes.frame.origin.y + zoom, attributes.size.width, attributes.size.height);
  57. if (self.param.wAlpha<1) {
  58. CGFloat collectionCenter = self.collectionView.frame.size.width / 2 ;
  59. CGFloat offset = self.collectionView.contentOffset.x ;
  60. CGFloat normalizedCenter = attributes.center.x - offset;
  61. CGFloat maxDistance = (self.itemSize.width) + self.minimumLineSpacing;
  62. CGFloat distance1 = MIN(fabs(collectionCenter - normalizedCenter), maxDistance);
  63. CGFloat ratio = (maxDistance - distance1) / maxDistance;
  64. CGFloat alpha = ratio * (1 - self.param.wAlpha) +self.param.wAlpha;
  65. attributes.alpha = alpha;
  66. }
  67. if (self.param.wZindex) {
  68. attributes.zIndex = zoom*100;
  69. }
  70. attributes.center = CGPointMake(attributes.center.x, (self.param.wPosition == BannerCellPositionBottom?attributes.center.y:self.collectionView.center.y) + zoom);
  71. }
  72. return array;
  73. }
  74. - (NSArray *)getCopyOfAttributes:(NSArray *)attributes
  75. {
  76. NSMutableArray *copyArr = [NSMutableArray new];
  77. for (UICollectionViewLayoutAttributes *attribute in attributes) {
  78. [copyArr addObject:[attribute copy]];
  79. }
  80. return copyArr;
  81. }
  82. - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
  83. if (self.param.wMarquee){
  84. return NO;
  85. }
  86. return ![self.collectionView isPagingEnabled];
  87. }
  88. /**
  89. * collectionView停止滚动时的偏移量
  90. */
  91. - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
  92. {
  93. if ([self.collectionView isPagingEnabled]||self.param.wMarquee) {
  94. return proposedContentOffset;
  95. }
  96. CGFloat offSetAdjustment = MAXFLOAT;
  97. CGFloat horizontalCenter = (CGFloat) (proposedContentOffset.x + self.collectionView.frame.size.width * self.param.wContentOffsetX);
  98. CGRect targetRect = CGRectMake(proposedContentOffset.x,
  99. 0.0,
  100. self.collectionView.bounds.size.width,
  101. self.collectionView.bounds.size.height);
  102. NSArray *attributes = [self layoutAttributesForElementsInRect:targetRect];
  103. NSPredicate *cellAttributesPredicate = [NSPredicate predicateWithBlock: ^BOOL(UICollectionViewLayoutAttributes * _Nonnull evaluatedObject,NSDictionary<NSString *,id> * _Nullable bindings){
  104. return (evaluatedObject.representedElementCategory == UICollectionElementCategoryCell);
  105. }];
  106. NSArray *cellAttributes = [attributes filteredArrayUsingPredicate: cellAttributesPredicate];
  107. UICollectionViewLayoutAttributes *currentAttributes;
  108. for (UICollectionViewLayoutAttributes *layoutAttributes in cellAttributes)
  109. {
  110. CGFloat itemHorizontalCenter = layoutAttributes.center.x;
  111. if (ABS(itemHorizontalCenter - horizontalCenter) < ABS(offSetAdjustment))
  112. {
  113. currentAttributes = layoutAttributes;
  114. offSetAdjustment = itemHorizontalCenter - horizontalCenter;
  115. }
  116. }
  117. CGFloat nextOffset = proposedContentOffset.x + offSetAdjustment;
  118. proposedContentOffset.x = nextOffset;
  119. CGFloat deltaX = proposedContentOffset.x - self.collectionView.contentOffset.x;
  120. CGFloat velX = velocity.x;
  121. if (fabs(deltaX) <= FLT_EPSILON || fabs(velX) <= FLT_EPSILON || (velX > 0.0 && deltaX > 0.0) || (velX < 0.0 && deltaX < 0.0))
  122. {
  123. }else if (velocity.x > 0.0){
  124. NSArray *revertedArray = [[attributes reverseObjectEnumerator] allObjects];
  125. BOOL found = YES;
  126. float proposedX = 0.0;
  127. for (UICollectionViewLayoutAttributes *layoutAttributes in revertedArray)
  128. {
  129. if(layoutAttributes.representedElementCategory == UICollectionElementCategoryCell)
  130. {
  131. CGFloat itemHorizontalCenter = layoutAttributes.center.x;
  132. if (itemHorizontalCenter > proposedContentOffset.x) {
  133. found = YES;
  134. proposedX = nextOffset + (currentAttributes.frame.size.width / 2) + (layoutAttributes.frame.size.width / 2);
  135. } else {
  136. break;
  137. }
  138. }
  139. }
  140. if (found) {
  141. proposedContentOffset.x = proposedX;
  142. proposedContentOffset.x += self.param.wLineSpacing;
  143. }
  144. }
  145. else if (velocity.x < 0.0)
  146. {
  147. for (UICollectionViewLayoutAttributes *layoutAttributes in cellAttributes)
  148. {
  149. CGFloat itemHorizontalCenter = layoutAttributes.center.x;
  150. if (itemHorizontalCenter > proposedContentOffset.x)
  151. {
  152. proposedContentOffset.x = nextOffset - ((currentAttributes.frame.size.width / 2) + (layoutAttributes.frame.size.width / 2));
  153. proposedContentOffset.x -= self.param.wLineSpacing;
  154. break;
  155. }
  156. }
  157. }
  158. proposedContentOffset.y = 0.0;
  159. return proposedContentOffset;
  160. }
  161. @end