UICollectionViewLeftAlignedLayout.m 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. //
  2. // UICollectionViewLeftAlignedLayout.m
  3. // SeeTheDay
  4. //
  5. // Created by lww on 2022/11/23.
  6. //
  7. #import "UICollectionViewLeftAlignedLayout.h"
  8. @interface UICollectionViewLayoutAttributes (LeftAligned)
  9. - (void)leftAlignFrameWithSectionInset:(UIEdgeInsets)sectionInset;
  10. @end
  11. @implementation UICollectionViewLayoutAttributes (LeftAligned)
  12. - (void)leftAlignFrameWithSectionInset:(UIEdgeInsets)sectionInset
  13. {
  14. CGRect frame = self.frame;
  15. frame.origin.x = sectionInset.left;
  16. self.frame = frame;
  17. }
  18. @end
  19. #pragma mark -
  20. @implementation UICollectionViewLeftAlignedLayout
  21. #pragma mark - UICollectionViewLayout
  22. - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
  23. NSArray *originalAttributes = [super layoutAttributesForElementsInRect:rect];
  24. NSMutableArray *updatedAttributes = [NSMutableArray arrayWithArray:originalAttributes];
  25. for (UICollectionViewLayoutAttributes *attributes in originalAttributes) {
  26. if (!attributes.representedElementKind) {
  27. NSUInteger index = [updatedAttributes indexOfObject:attributes];
  28. updatedAttributes[index] = [self layoutAttributesForItemAtIndexPath:attributes.indexPath];
  29. }
  30. }
  31. return updatedAttributes;
  32. }
  33. - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
  34. UICollectionViewLayoutAttributes* currentItemAttributes = [[super layoutAttributesForItemAtIndexPath:indexPath] copy];
  35. UIEdgeInsets sectionInset = [self evaluatedSectionInsetForItemAtIndex:indexPath.section];
  36. BOOL isFirstItemInSection = indexPath.item == 0;
  37. CGFloat layoutWidth = CGRectGetWidth(self.collectionView.frame) - sectionInset.left - sectionInset.right;
  38. if (isFirstItemInSection) {
  39. [currentItemAttributes leftAlignFrameWithSectionInset:sectionInset];
  40. return currentItemAttributes;
  41. }
  42. NSIndexPath* previousIndexPath = [NSIndexPath indexPathForItem:indexPath.item-1 inSection:indexPath.section];
  43. CGRect previousFrame = [self layoutAttributesForItemAtIndexPath:previousIndexPath].frame;
  44. CGFloat previousFrameRightPoint = previousFrame.origin.x + previousFrame.size.width;
  45. CGRect currentFrame = currentItemAttributes.frame;
  46. CGRect strecthedCurrentFrame = CGRectMake(sectionInset.left,
  47. currentFrame.origin.y,
  48. layoutWidth,
  49. currentFrame.size.height);
  50. // if the current frame, once left aligned to the left and stretched to the full collection view
  51. // width intersects the previous frame then they are on the same line
  52. BOOL isFirstItemInRow = !CGRectIntersectsRect(previousFrame, strecthedCurrentFrame);
  53. if (isFirstItemInRow) {
  54. // make sure the first item on a line is left aligned
  55. [currentItemAttributes leftAlignFrameWithSectionInset:sectionInset];
  56. return currentItemAttributes;
  57. }
  58. CGRect frame = currentItemAttributes.frame;
  59. frame.origin.x = previousFrameRightPoint + [self evaluatedMinimumInteritemSpacingForSectionAtIndex:indexPath.section];
  60. currentItemAttributes.frame = frame;
  61. return currentItemAttributes;
  62. }
  63. - (CGFloat)evaluatedMinimumInteritemSpacingForSectionAtIndex:(NSInteger)sectionIndex
  64. {
  65. if ([self.collectionView.delegate respondsToSelector:@selector(collectionView:layout:minimumInteritemSpacingForSectionAtIndex:)]) {
  66. id<UICollectionViewDelegateLeftAlignedLayout> delegate = (id<UICollectionViewDelegateLeftAlignedLayout>)self.collectionView.delegate;
  67. return [delegate collectionView:self.collectionView layout:self minimumInteritemSpacingForSectionAtIndex:sectionIndex];
  68. } else {
  69. return self.minimumInteritemSpacing;
  70. }
  71. }
  72. - (UIEdgeInsets)evaluatedSectionInsetForItemAtIndex:(NSInteger)index
  73. {
  74. if ([self.collectionView.delegate respondsToSelector:@selector(collectionView:layout:insetForSectionAtIndex:)]) {
  75. id<UICollectionViewDelegateLeftAlignedLayout> delegate = (id<UICollectionViewDelegateLeftAlignedLayout>)self.collectionView.delegate;
  76. return [delegate collectionView:self.collectionView layout:self insetForSectionAtIndex:index];
  77. } else {
  78. return self.sectionInset;
  79. }
  80. }
  81. @end