之前看到過的一篇文章
對collectionView的使用總結的非常好:“iOS6新特征:UICollectionView介紹”
流水布局在現在的應用中很常見了,簡單的研究了下,實現下面的功能
那我這里就簡單介紹下 UICollectionViewFlowLayout 常用的幾個方法,通過這幾個方法就能辦到上面的效果了
1、布局
/** * 用來做布局的初始化操作(不建議在init方法中進行布局的初始化操作) */ - (void)prepareLayout { [super prepareLayout]; }
在這里設置為水平滾動
self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
2、排布rect范圍內的控件
/** 數組中保存的是 UICollectionViewLayoutAttributes *attrs; 1.一個cell對應一個UICollectionViewLayoutAttributes對象 2.UICollectionViewLayoutAttributes對象決定了cell的frame */ /** * 這個方法的返回值是一個數組(數組里面存放着rect范圍內所有元素的布局屬性) * 這個方法的返回值決定了rect范圍內所有元素的排布(frame) */ - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { // 獲得super已經計算好的布局屬性 NSArray *array = [super layoutAttributesForElementsInRect:rect]; return array; }
在這個方法中可以先拿到系統計算好的布局屬性,然后遍歷,對cell進行微調
// 獲得super已經計算好的布局屬性 NSArray *array = [super layoutAttributesForElementsInRect:rect]; // 計算collectionView最中心點的x值 CGFloat centerX = self.collectionView.contentOffset.x + self.collectionView.frame.size.width * 0.5; // 在原有布局屬性的基礎上,進行微調 for (UICollectionViewLayoutAttributes *attrs in array) { // cell的中心點x 和 collectionView最中心點的x值 的間距 CGFloat delta = ABS(attrs.center.x - centerX); // 根據間距值 計算 cell的縮放比例 CGFloat scale = 1 - delta / self.collectionView.frame.size.width; // 設置縮放比例 attrs.transform = CGAffineTransformMakeScale(scale, scale); }
3、重新刷新布局
/** * 當collectionView的顯示范圍發生改變的時候,是否需要重新刷新布局 * 一旦重新刷新布局,就會重新調用下面的方法:(也就上面那兩) 1.prepareLayout 2.layoutAttributesForElementsInRect:方法 */ - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { return YES; }
因為在滾動之后都需要實時對attrs.transform進行改變,返回yes代表rect發生改變時調用1、2方法重新布局 達到滾動到中間時放大的效果
4、collectionView停止滾動時的偏移量
/** * 這個方法的返回值,就決定了collectionView停止滾動時的偏移量 * 這個方法在滾動松手的那一刻調用 */ - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity { // proposedContentOffset 預計的位置(滾動結束時) return proposedContentOffset; }
在這個方法中判斷滾動真正停止時哪個cell里中心點最近,計算出最近的cell里中心點的間距(有正負之分),加上系統預計的ContentOffset就能修改實際滾到的位置。
核心代碼:
// 計算出最終顯示的矩形框 CGRect rect; rect.origin.y = 0; rect.origin.x = proposedContentOffset.x; rect.size = self.collectionView.frame.size; // 獲得super已經計算好的布局屬性 NSArray *array = [super layoutAttributesForElementsInRect:rect]; // 計算collectionView最中心點的x值 CGFloat centerX = proposedContentOffset.x + self.collectionView.frame.size.width * 0.5; // 存放最小的間距值 CGFloat minDelta = MAXFLOAT; for (UICollectionViewLayoutAttributes *attrs in array) { if (ABS(minDelta) > ABS(attrs.center.x - centerX)) { minDelta = attrs.center.x - centerX; } } // 修改原有的偏移量 proposedContentOffset.x += minDelta; return proposedContentOffset;