五個UICollectionView常用的知識點

在路上重名了啊發表於2019-02-10
  • 一:監聽滾動停止的時刻
  • 二、監聽reloadData重新整理列表完畢的時機
  • 三、自由拖拽
  • 四、瀑布流
  • 五、浮動的Header

一:監聽滾動停止的時刻

場景1、手動拖拽螢幕停止

五個UICollectionView常用的知識點

場景2、呼叫scrollToRow停止

五個UICollectionView常用的知識點

場景3、呼叫setContentOffset停止

self.tableView.setContentOffset(CGPoint.init(x: 0, y: 0), animated: false)
print("執行這行程式碼的時候,已經滾動完畢")
複製程式碼

二、監聽reloadData重新整理列表完畢的時機

詳情參考監聽reloadData重新整理列表完畢的時機

  • 方法1、通過layoutIfNeeded方法,強制重繪並等待完成。
  • 方法2、reloadData方法會在主執行緒執行,通過GCD,使後續操作排隊在reloadData後面執行。一次runloop有兩個機會執行GCD dispatch main queue中的任務,分別在休眠前和被喚醒後。設定listViewlayoutIfNeeded為YES,在即將進入休眠時執行非同步任務,重繪一次介面。
  • 方法3、自定義UICollectionViewUITableViewlayoutSubviews之後當作reloadData完成(複雜,但可以更好的理解方法一)

三、自由拖拽

五個UICollectionView常用的知識點

一、iOS9之前思路:

  • 第一步 :給UICollectionviewCell新增一個長按手勢UILongPressGestureRecognizer,通過代理傳遞到UIViewController中。
  • 第二步 :開始長按時(UIGestureRecognizerStateBegan)對cell進行截圖並且隱藏cell
  • 第三步 :移動時(UIGestureRecognizerStateChanged)移動截圖,遍歷得到截圖移動到哪個cell的位置。呼叫方法moveItemAtIndexPath:toIndexPath:調換兩個cell的位置,並且更新資料來源的順序。
  • 第四步 :停止時(UIGestureRecognizerStateEnded)移除截圖,顯示cell

參考部落格:

[iOSUI 進階拖] 拽排序的實現

DraggingSort

LXReorderableCollectionViewFlowLayout

XWDragCellCollectionView

CollectionViewCellDragExchange

二、iOS9之後思路:

  • 第一步:給UICollectionviewCell新增一個長按手勢UILongPressGestureRecognizer,通過代理傳遞到UIViewController中。
  • 第二步:開始長按時(UIGestureRecognizerStateBegan)對cell進行截圖並且隱藏cell。呼叫beginInteractiveMovementForItem
  • 第三步:移動時(UIGestureRecognizerStateChanged)移動截圖。呼叫updateInteractiveMovementTargetPosition
  • 第四步:停止時(UIGestureRecognizerStateEnded)移除截圖,顯示cell。呼叫endInteractiveMovement
// Support for reordering
@available(iOS 9.0, *)
open func beginInteractiveMovementForItem(at indexPath: IndexPath) -> Bool // returns NO if reordering was prevented from beginning - otherwise YES

@available(iOS 9.0, *)
open func updateInteractiveMovementTargetPosition(_ targetPosition: CGPoint)

@available(iOS 9.0, *)
open func endInteractiveMovement()

@available(iOS 9.0, *)
open func cancelInteractiveMovement()
複製程式碼

參考部落格:

iOS UICollectionView高階用法(長按自由移動cell)-新

四、瀑布流

五個UICollectionView常用的知識點

實現瀑布流的基本原理找到最短的列,然後把item放到最短的列下面

如下圖所示,由於第三列最短,所以第八個Item新增到第三列下面。

五個UICollectionView常用的知識點

既然要找到 最短的列 ,則就需要用一個資料來儲存每一列的Y值,推薦 陣列 (相對來說效能比 字典 好)。XRWaterfallLayout使用 字典 來儲存,相比較 陣列 的下標直接獲取列的高度, 字典 多做了部分雜湊操作。做瀑布流,圖片的尺寸就可能是不固定的,圖片的尺寸可以伺服器提前返回,然後cell直接設定大小。

主要需要重寫三個系統方法:詳情參考實現:XRWaterfallLayout 1、- (void)prepareLayout 2、- (CGSize)collectionViewContentSize 3、- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect

五、浮動的Header

五個UICollectionView常用的知識點

一、在iOS9

UICollectionView的頭部檢視也能像tableViewheader一樣出現懸浮掛住的效果。

UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init]; 
//header 
flowLayout.sectionHeadersPinToVisibleBounds = YES; 
//footer
flowLayout.sectionFootersPinToVisibleBounds = YES;
複製程式碼

二、在iOS9.0

需要自定義UICollectionViewFlowLayout

#import <UIKit/UIKit.h>
@protocol LZSFloatHeaderFlowLayoutDelegate <NSObject>
-(void)sectionDidFloat:(NSInteger)section;
@end

@interface LZSFloatHeaderFlowLayout : UICollectionViewFlowLayout
@property (nonatomic, weak) id<LZSFloatHeaderFlowLayoutDelegate> mDelegate;
@end
複製程式碼
#import "LZSFloatHeaderFlowLayout.h"

@interface LZSFloatHeaderFlowLayout()
@property (nonatomic, strong) NSMutableDictionary<NSNumber*, NSNumber*>* mSectionOffsetYDic;
@end

@implementation LZSFloatHeaderFlowLayout
-(NSMutableDictionary<NSNumber *,NSNumber *> *)mSectionOffsetYDic {
    if ( !_mSectionOffsetYDic ) {
        _mSectionOffsetYDic = [NSMutableDictionary dictionary];
    }
    return _mSectionOffsetYDic;
}
- (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect {
    NSMutableArray *answer = [[super layoutAttributesForElementsInRect:rect] mutableCopy];
    NSMutableIndexSet *missingSections = [NSMutableIndexSet indexSet];
    for (NSUInteger idx=0; idx<[answer count]; idx++) {
        UICollectionViewLayoutAttributes *layoutAttributes = answer[idx];
        if (layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) {
            [missingSections addIndex:layoutAttributes.indexPath.section];  // remember that we need to layout header for this section
        }
        if ([layoutAttributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) {
            [answer removeObjectAtIndex:idx];  // remove layout of header done by our super, we will do it right later
            idx--;
        }
    }
    // layout all headers needed for the rect using self code
    [missingSections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:idx];
        UICollectionViewLayoutAttributes *layoutAttributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader
                                                                                                  atIndexPath:indexPath];
        [answer addObject:layoutAttributes];
    }];
    return answer;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind
                                                                     atIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewLayoutAttributes *attributes = [super layoutAttributesForSupplementaryViewOfKind:kind
                                                                                         atIndexPath:indexPath];
    if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
        UICollectionView * const cv = self.collectionView;
        CGPoint const contentOffset = cv.contentOffset;
        CGPoint nextHeaderOrigin = CGPointMake(INFINITY, INFINITY);
        
        if (indexPath.section+1 < [cv numberOfSections]) {
            NSIndexPath* tIndexPath = [NSIndexPath indexPathForItem:0 inSection:indexPath.section+1]
            UICollectionViewLayoutAttributes *nextHeaderAttributes = [super layoutAttributesForSupplementaryViewOfKind:kind
                                                                                                           atIndexPath:tIndexPath];
            nextHeaderOrigin = nextHeaderAttributes.frame.origin;
        }
        CGRect frame = attributes.frame;
        if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
            frame.origin.y = MIN(MAX(contentOffset.y, frame.origin.y), nextHeaderOrigin.y - CGRectGetHeight(frame));
        }
        else { // UICollectionViewScrollDirectionHorizontal
            frame.origin.x = MIN(MAX(contentOffset.x, frame.origin.x), nextHeaderOrigin.x - CGRectGetWidth(frame));
        }
        attributes.zIndex = 1024;
        attributes.frame = frame;
        if ( self.mSectionOffsetYDic[@(indexPath.section)] && (self.mSectionOffsetYDic[@(indexPath.section)].integerValue != frame.origin.y) ) {
            if ( [self.mDelegate respondsToSelector:@selector(sectionDidFloat:)] ) {
                [self.mDelegate sectionDidFloat:indexPath.section];
            }
        }
        self.mSectionOffsetYDic[@(indexPath.section)] = @(frame.origin.y);
    }
    return attributes;
}
- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingSupplementaryElementOfKind:(NSString *)kind
                                                                                        atIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind:kind
                                                                                        atIndexPath:indexPath];
    return attributes;
}
- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingSupplementaryElementOfKind:(NSString *)kind
                                                                                         atIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind:kind
                                                                                        atIndexPath:indexPath];
    return attributes;
}
- (BOOL) shouldInvalidateLayoutForBoundsChange:(CGRect)newBound {
    return YES;
}
複製程式碼

相關文章