UICollectionView自定義布局掌握的五個方法:
// 作用:計算cell位置,只要計算一次,前提:cell的位置一開始就是固定
// 什么時候調(diào)用:第一次布局調(diào)用,每次刷新collectionView也會調(diào)用// 注意:必須要調(diào)用[super prepareLayout]
- (void)prepareLayout{
[super prepareLayout];
}
// UICollectionViewLayoutAttributes:cell的布局對象
// 每一個cell對應(yīng)UICollectionViewLayoutAttributes
// UICollectionViewLayoutAttributes用來描述cell的布局
// UICollectionViewLayoutAttributes就是cell
// 作用:指定一個區(qū)域,就會返回這個區(qū)域內(nèi)的所有cell布局
// 這個可以一次性返回所有cell布局,也可以分批方法
// 操作cell布局
- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
// 獲取顯示范圍
CGRect visableRect = self.collectionView.bounds;
NSArray *attrs = [super layoutAttributesForElementsInRect:visableRect];
for (UICollectionViewLayoutAttributes *attr in attrs) {
}
NSLog(@"%@",attrs);
return attrs;
}
// Invalidate:刷新
// 在拖動內(nèi)容是否允許屬性布局
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{
return YES;
}
// 什么時候調(diào)用:在拖動的時候,手指抬起調(diào)用
// 作用:返回最終偏移量,最終collectionView停到哪個位置
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
// 第一個參數(shù):就是最終偏移量, 手指快速拖動視圖減速直到停止的偏移量 == proposedContentOffset參數(shù)
CGPoint targetOffset = [super targetContentOffsetForProposedContentOffset:proposedContentOffset withScrollingVelocity:velocity];
// self.collectionView.contentOffset 獲取手指抬起時,collectionView的偏移量
NSLog(@"%@ %@", NSStringFromCGPoint(self.collectionView.contentOffset),NSStringFromCGPoint(proposedContentOffset));
return targetOffset;
}
// 作用:計算collectionView滾動范圍
- (CGSize)collectionViewContentSize{
return [super collectionViewContentSize];
}
如下效果圖所示,原理其實還是collectionView自定義其layout
自定義FlowLayout繼承UICollectionViewFlowLayout,其.m文件實現(xiàn)如下:
@implementation FlowLayout
// 作用:計算cell位置,只要計算一次,前提:cell的位置一開始就是固定
// 什么時候調(diào)用:第一次布局調(diào)用,每次刷新collectionView也會調(diào)用
// 注意:必須要調(diào)用[super prepareLayout]
//- (void)prepareLayout
//{
// [super prepareLayout];
//
//}
// UICollectionViewLayoutAttributes:cell的布局對象
// 每一個cell對應(yīng)UICollectionViewLayoutAttributes
// UICollectionViewLayoutAttributes用來描述cell的布局
// UICollectionViewLayoutAttributes就是cell
// 作用:指定一個區(qū)域,就會返回這個區(qū)域內(nèi)的所有cell布局
// 這個可以一次性返回所有cell布局,也可以分批方法
// 操作cell布局
- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
// 哪些cell需要進(jìn)行縮放,顯示cell才需要做縮放,獲取顯示出來cell布局,獲取顯示范圍
// 問題:什么時候縮放,什么時候放大
// 離中心點越近,cell越大,離中心點越遠(yuǎn),cell越小
// 縮放跟中心點成反比
// 計算中心點
// 獲取顯示范圍
CGRect visableRect = self.collectionView.bounds;
NSArray *attrs = [super layoutAttributesForElementsInRect:visableRect];
;
for (UICollectionViewLayoutAttributes *attr in attrs) {
// 獲取距離中心點的位置
CGFloat delta =fabs(attr.center.x - (self.collectionView.contentOffset.x + XMGScreenW * 0.5));
// 每個cell進(jìn)行縮放 1 ~ 0.5
CGFloat scale = 1 - delta / (XMGScreenW * 0.5) * 0.25;
attr.transform = CGAffineTransformMakeScale(scale, scale);
}
return attrs;
}
// 作用:
// Invalidate:刷新
// 在拖動內(nèi)容是否允許屬性布局
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
return YES;
}
// 什么時候調(diào)用:在拖動的時候,手指抬起調(diào)用
// 作用:返回最終偏移量,最終collectionView停到哪個位置
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
// 定位:判斷下誰離中心點近,就顯示在中心位置
// 判斷下最終顯示那塊區(qū)域
// 獲取最終顯示區(qū)域
CGRect targetRect = CGRectMake(proposedContentOffset.x, 0, XMGScreenW, MAXFLOAT);
// 獲取最終顯示區(qū)域下所有cell,去判斷下哪個離中心點近
NSArray *attrs = [super layoutAttributesForElementsInRect:targetRect];
// 判斷下哪個離中心點
CGFloat minDelta = MAXFLOAT;
for (UICollectionViewLayoutAttributes *attr in attrs) {
// 獲取中心點距離
CGFloat delta =attr.center.x - (self.collectionView.contentOffset.x + XMGScreenW * 0.5);
if (fabs(delta) <fabs(minDelta)) {
minDelta = delta;
}
}
proposedContentOffset.x += minDelta;
if (proposedContentOffset.x < 0) {
proposedContentOffset.x = 0;
}
NSLog(@"%f",proposedContentOffset.x);
return proposedContentOffset;
}
// 作用:計算collectionView滾動范圍
//- (CGSize)collectionViewContentSize
//{
// return [super collectionViewContentSize];
//}
@end
調(diào)用(特地介紹以下這種寫法:其實這是C語言的逗號表達(dá)式,忘記是什么鬼請問度娘)
FlowLayout *layout = ({
layout = [[FlowLayout alloc] init];
// 設(shè)置cell尺寸
layout.itemSize = CGSizeMake(160, 160);
// 設(shè)置最小行間距為0
layout.minimumLineSpacing = 30;
// 設(shè)置滾動方向
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
// 設(shè)置額外滾動區(qū)域
CGFloat inset = (self.view.bounds.size.width - 160) * 0.5;
layout.sectionInset = UIEdgeInsetsMake(0, inset, 0, inset);
layout;
});